+version 0.8.2:
+
+ - ACPI support
+ - PC VGA BIOS fixes
+ - switch to OpenBios for SPARC targets (Blue Swirl)
+ - VNC server fixes
+ - MIPS FPU support (Marius Groeger)
+ - Solaris/SPARC host support (Ben Taylor)
+ - PPC breakpoints and single stepping (Jason Wessel)
+ - USB updates (Paul Brook)
+ - UDP/TCP/telnet character devices (Jason Wessel)
+ - Windows sparse file support (Frediano Ziglio)
+ - RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
+ - PCNET NIC support (Antony T Curtis)
+ - Support for variable frequency host CPUs
+ - Workaround for win32 SMP hosts
+ - Support for AMD Flash memories (Jocelyn Mayer)
+ - Audio capture to WAV files support (malc)
+
version 0.8.1:
- USB tablet support (Brad Campbell, Anthony Liguori)
+# Makefile for QEMU.
+
XEN_ROOT=../..
include $(XEN_ROOT)/tools/Rules.mk
-include config-host.mak
+.PHONY: all clean distclean dvi info install install-doc tar tarbin \
+ speed test test2 html dvi info
+
CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I.
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
+ifeq ($(ARCH),sparc)
+CFLAGS+=-mcpu=ultrasparc
+endif
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
DOCS=
endif
-all: $(DOCS)
- for d in $(TARGET_DIRS); do \
- $(MAKE) -C $$d $@ || exit 1 ; \
- done
+TOOLS=
+all: $(TOOLS) $(DOCS) recurse-all
+
+subdir-%:
+ $(MAKE) -C $(subst subdir-,,$@) all
+
+recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
+
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
distclean: clean
rm -f config-host.mak config-host.h $(DOCS)
+ rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
# $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
# mkdir -p "$(DESTDIR)$(datadir)"
# for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-# video.x proll.elf linux_boot.bin; do \
+# video.x openbios-sparc32 linux_boot.bin; do \
# $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
# done
ifndef CONFIG_WIN32
perl -w $(SRC_PATH)/texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
+info: qemu-doc.info qemu-tech.info
+
+dvi: qemu-doc.dvi qemu-tech.dvi
+
+html: qemu-doc.html qemu-tech.html
+
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
- $(datadir)/proll.elf \
+ $(datadir)/openbios-sparc32 \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
TARGET_ARCH2=armeb
endif
endif
+ifeq ($(TARGET_ARCH),sh4)
+ ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
+ TARGET_ARCH2=sh4eb
+ endif
+endif
ifeq ($(TARGET_ARCH),mips)
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=mipsel
endif
ifeq ($(ARCH),sparc)
-CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+ifeq ($(CONFIG_SOLARIS),yes)
+CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
+LDFLAGS+=-m32
+OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
+else
+CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
endif
+endif
ifeq ($(ARCH),sparc64)
-CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
LDFLAGS+=-m64
+LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
main.o: CFLAGS+=-p
endif
-OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
+OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
+ elfload.o linuxload.o
+ifdef TARGET_HAS_BFLT
+OBJS+= flatload.o
+endif
+
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
+AUDIODRV+= wavcapture.o
+
+# SCSI layer
+VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
# USB layer
-VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o
+VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
# PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o
+VL_OBJS+= ne2000.o rtl8139.o pcnet.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
-VL_OBJS+= cirrus_vga.o mixeng.o parallel.o
+VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
+VL_OBJS+= usb-uhci.o
VL_OBJS+= piix4acpi.o
VL_OBJS+= xenstore.o
DEFINES += -DHAS_AUDIO
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
+VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_ARCH), mips)
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
-VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o
+VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
else
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
+VL_OBJS+= versatile_pci.o
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
-VL_LIBS=-lutil
+VL_LIBS=-lutil -lrt
endif
endif
endif
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
+ifeq ($(ARCH),sparc64)
+VL_LDFLAGS+=-m64
+VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
+endif
+
ifdef CONFIG_WIN32
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
endif
loader.o: loader.c elf_ops.h
+acpi.o: acpi.c acpi-dsdt.hex
+
+ifdef BUILD_ACPI_TABLES
+$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
+ iasl -tc -p $@ $<
+endif
+
ifeq ($(TARGET_ARCH), sh4)
op.o: op.c op_mem.c cpu.h
op_helper.o: op_helper.c exec.h cpu.h
tc58128.o: tc58128.c
endif
+$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
+
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
short term:
----------
-- support variable tsc freq
+- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
+- support variable tsc freq
- USB host async
- IDE async
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
-- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
-- commit message if execution of code in IO memory
- update doc: PCI infos.
-- VNC patch + Synaptic patch.
- basic VGA optimizations
-- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
-- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
-- fix arm fpu rounding (at least for float->integer conversions)
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
-- SPR_ENCODE() not useful
- enable shift optimizations ?
linux-user specific:
-0.8.1
\ No newline at end of file
+0.8.2
\ No newline at end of file
.size_in_usec_in = 1,
.size_in_usec_out = 1,
#endif
- .pcm_name_out = "hw:0,0",
- .pcm_name_in = "hw:0,0",
+ .pcm_name_out = "default",
+ .pcm_name_in = "default",
#ifdef HIGH_LATENCY
.buffer_size_in = 400000,
.period_size_in = 400000 / 4,
}
}
- mixeng_clear (src, written);
rpos = (rpos + written) % hw->samples;
samples -= written;
len -= written;
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
+ obt_as.endianness = endianness;
- audio_pcm_init_info (
- &hw->info,
- &obt_as,
- audio_need_to_swap_endian (endianness)
- );
+ audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
+ obt_as.endianness = endianness;
- audio_pcm_init_info (
- &hw->info,
- &obt_as,
- audio_need_to_swap_endian (endianness)
- );
+ audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
/* #define DEBUG_PLIVE */
/* #define DEBUG_LIVE */
/* #define DEBUG_OUT */
+/* #define DEBUG_CAPTURE */
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
if (cond) {
static int shown;
- AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
+ AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
if (!shown) {
shown = 1;
AUD_log (NULL, "Save all your work and restart without audio\n");
AUD_log (NULL, "invalid(%d)", as->fmt);
break;
}
+
+ AUD_log (NULL, " endianness=");
+ switch (as->endianness) {
+ case 0:
+ AUD_log (NULL, "little");
+ break;
+ case 1:
+ AUD_log (NULL, "big");
+ break;
+ default:
+ AUD_log (NULL, "invalid");
+ break;
+ }
AUD_log (NULL, "\n");
}
-static int audio_validate_settigs (audsettings_t *as)
+static int audio_validate_settings (audsettings_t *as)
{
int invalid;
invalid = as->nchannels != 1 && as->nchannels != 2;
+ invalid |= as->endianness != 0 && as->endianness != 1;
switch (as->fmt) {
case AUD_FMT_S8:
}
invalid |= as->freq <= 0;
-
- if (invalid) {
- return -1;
- }
- return 0;
+ return invalid ? -1 : 0;
}
static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
return info->freq == as->freq
&& info->nchannels == as->nchannels
&& info->sign == sign
- && info->bits == bits;
+ && info->bits == bits
+ && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
}
-void audio_pcm_init_info (
- struct audio_pcm_info *info,
- audsettings_t *as,
- int swap_endian
- )
+void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
{
int bits = 8, sign = 0;
info->shift = (as->nchannels == 2) + (bits == 16);
info->align = (1 << info->shift) - 1;
info->bytes_per_second = info->freq << info->shift;
- info->swap_endian = swap_endian;
+ info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
}
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
int shift = info->nchannels - 1;
short s = INT16_MAX;
- if (info->swap_endian) {
+ if (info->swap_endianness) {
s = bswap16 (s);
}
}
}
+/*
+ * Capture
+ */
+static void noop_conv (st_sample_t *dst, const void *src,
+ int samples, volume_t *vol)
+{
+ (void) src;
+ (void) dst;
+ (void) samples;
+ (void) vol;
+}
+
+static CaptureVoiceOut *audio_pcm_capture_find_specific (
+ AudioState *s,
+ audsettings_t *as
+ )
+{
+ CaptureVoiceOut *cap;
+
+ for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+ if (audio_pcm_info_eq (&cap->hw.info, as)) {
+ return cap;
+ }
+ }
+ return NULL;
+}
+
+static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
+{
+ struct capture_callback *cb;
+
+#ifdef DEBUG_CAPTURE
+ dolog ("notification %d sent\n", cmd);
+#endif
+ for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+ cb->ops.notify (cb->opaque, cmd);
+ }
+}
+
+static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
+{
+ if (cap->hw.enabled != enabled) {
+ audcnotification_e cmd;
+ cap->hw.enabled = enabled;
+ cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
+ audio_notify_capture (cap, cmd);
+ }
+}
+
+static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
+{
+ HWVoiceOut *hw = &cap->hw;
+ SWVoiceOut *sw;
+ int enabled = 0;
+
+ for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+ if (sw->active) {
+ enabled = 1;
+ break;
+ }
+ }
+ audio_capture_maybe_changed (cap, enabled);
+}
+
+static void audio_detach_capture (HWVoiceOut *hw)
+{
+ SWVoiceCap *sc = hw->cap_head.lh_first;
+
+ while (sc) {
+ SWVoiceCap *sc1 = sc->entries.le_next;
+ SWVoiceOut *sw = &sc->sw;
+ CaptureVoiceOut *cap = sc->cap;
+ int was_active = sw->active;
+
+ if (sw->rate) {
+ st_rate_stop (sw->rate);
+ sw->rate = NULL;
+ }
+
+ LIST_REMOVE (sw, entries);
+ LIST_REMOVE (sc, entries);
+ qemu_free (sc);
+ if (was_active) {
+ /* We have removed soft voice from the capture:
+ this might have changed the overall status of the capture
+ since this might have been the only active voice */
+ audio_recalc_and_notify_capture (cap);
+ }
+ sc = sc1;
+ }
+}
+
+static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
+{
+ CaptureVoiceOut *cap;
+
+ audio_detach_capture (hw);
+ for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+ SWVoiceCap *sc;
+ SWVoiceOut *sw;
+ HWVoiceOut *hw_cap = &cap->hw;
+
+ sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
+ if (!sc) {
+ dolog ("Could not allocate soft capture voice (%zu bytes)\n",
+ sizeof (*sc));
+ return -1;
+ }
+
+ sc->cap = cap;
+ sw = &sc->sw;
+ sw->hw = hw_cap;
+ sw->info = hw->info;
+ sw->empty = 1;
+ sw->active = hw->enabled;
+ sw->conv = noop_conv;
+ sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
+ sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
+ if (!sw->rate) {
+ dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
+ qemu_free (sw);
+ return -1;
+ }
+ LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
+ LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
+#ifdef DEBUG_CAPTURE
+ asprintf (&sw->name, "for %p %d,%d,%d",
+ hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
+ dolog ("Added %s active = %d\n", sw->name, sw->active);
+#endif
+ if (sw->active) {
+ audio_capture_maybe_changed (cap, 1);
+ }
+ }
+ return 0;
+}
+
/*
* Hard voice (capture)
*/
}
if (live == hwsamples) {
+#ifdef DEBUG_OUT
+ dolog ("%s is full %d\n", sw->name, live);
+#endif
return 0;
}
hw = sw->hw;
if (sw->active != on) {
SWVoiceOut *temp_sw;
+ SWVoiceCap *sc;
if (on) {
- int total;
-
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
}
-
- if (sw->empty) {
- total = 0;
- }
}
else {
if (hw->enabled) {
hw->pending_disable = nb_active == 1;
}
}
+
+ for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+ sc->sw.active = hw->enabled;
+ if (hw->enabled) {
+ audio_capture_maybe_changed (sc->cap, 1);
+ }
+ }
sw->active = on;
}
}
}
ldebug (
- "%s: get_avail live %d ret %lld\n",
+ "%s: get_avail live %d ret %" PRId64 "\n",
SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
);
dead = sw->hw->samples - live;
#ifdef DEBUG_OUT
- dolog ("%s: get_free live %d dead %d ret %lld\n",
+ dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
SW_NAME (sw),
live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
#endif
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
}
+static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
+{
+ int n;
+
+ if (hw->enabled) {
+ SWVoiceCap *sc;
+
+ for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+ SWVoiceOut *sw = &sc->sw;
+ int rpos2 = rpos;
+
+ n = samples;
+ while (n) {
+ int till_end_of_hw = hw->samples - rpos2;
+ int to_write = audio_MIN (till_end_of_hw, n);
+ int bytes = to_write << hw->info.shift;
+ int written;
+
+ sw->buf = hw->mix_buf + rpos2;
+ written = audio_pcm_sw_write (sw, NULL, bytes);
+ if (written - bytes) {
+ dolog ("Could not mix %d bytes into a capture "
+ "buffer, mixed %d\n",
+ bytes, written);
+ break;
+ }
+ n -= to_write;
+ rpos2 = (rpos2 + to_write) % hw->samples;
+ }
+ }
+ }
+
+ n = audio_MIN (samples, hw->samples - rpos);
+ mixeng_clear (hw->mix_buf + rpos, n);
+ mixeng_clear (hw->mix_buf, samples - n);
+}
+
static void audio_run_out (AudioState *s)
{
HWVoiceOut *hw = NULL;
while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
int played;
- int live, free, nb_live, cleanup_required;
+ int live, free, nb_live, cleanup_required, prev_rpos;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!nb_live) {
}
if (hw->pending_disable && !nb_live) {
+ SWVoiceCap *sc;
#ifdef DEBUG_OUT
dolog ("Disabling voice\n");
#endif
hw->enabled = 0;
hw->pending_disable = 0;
hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+ for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+ sc->sw.active = 0;
+ audio_recalc_and_notify_capture (sc->cap);
+ }
continue;
}
continue;
}
+ prev_rpos = hw->rpos;
played = hw->pcm_ops->run_out (hw);
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
if (played) {
hw->ts_helper += played;
+ audio_capture_mix_and_clear (hw, prev_rpos, played);
}
cleanup_required = 0;
}
if (cleanup_required) {
- restart:
- for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+ SWVoiceOut *sw1;
+
+ sw = hw->sw_head.lh_first;
+ while (sw) {
+ sw1 = sw->entries.le_next;
if (!sw->active && !sw->callback.fn) {
#ifdef DEBUG_PLIVE
dolog ("Finishing with old voice\n");
#endif
audio_close_out (s, sw);
- goto restart; /* play it safe */
}
+ sw = sw1;
}
}
}
}
}
+static void audio_run_capture (AudioState *s)
+{
+ CaptureVoiceOut *cap;
+
+ for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
+ int live, rpos, captured;
+ HWVoiceOut *hw = &cap->hw;
+ SWVoiceOut *sw;
+
+ captured = live = audio_pcm_hw_get_live_out (hw);
+ rpos = hw->rpos;
+ while (live) {
+ int left = hw->samples - rpos;
+ int to_capture = audio_MIN (live, left);
+ st_sample_t *src;
+ struct capture_callback *cb;
+
+ src = hw->mix_buf + rpos;
+ hw->clip (cap->buf, src, to_capture);
+ mixeng_clear (src, to_capture);
+
+ for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+ cb->ops.capture (cb->opaque, cap->buf,
+ to_capture << hw->info.shift);
+ }
+ rpos = (rpos + to_capture) % hw->samples;
+ live -= to_capture;
+ }
+ hw->rpos = rpos;
+
+ for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+ if (!sw->active && sw->empty) {
+ continue;
+ }
+
+ if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
+ dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
+ captured, sw->total_hw_samples_mixed);
+ captured = sw->total_hw_samples_mixed;
+ }
+
+ sw->total_hw_samples_mixed -= captured;
+ sw->empty = sw->total_hw_samples_mixed == 0;
+ }
+ }
+}
+
static void audio_timer (void *opaque)
{
AudioState *s = opaque;
audio_run_out (s);
audio_run_in (s);
+ audio_run_capture (s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
HWVoiceIn *hwi = NULL;
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+ SWVoiceCap *sc;
+
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
hwo->pcm_ops->fini_out (hwo);
+
+ for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
+ CaptureVoiceOut *cap = sc->cap;
+ struct capture_callback *cb;
+
+ for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+ cb->ops.destroy (cb->opaque);
+ }
+ }
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
LIST_INIT (&s->hw_head_out);
LIST_INIT (&s->hw_head_in);
+ LIST_INIT (&s->cap_head);
atexit (audio_atexit);
s->ts = qemu_new_timer (vm_clock, audio_timer, s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
return s;
}
+
+CaptureVoiceOut *AUD_add_capture (
+ AudioState *s,
+ audsettings_t *as,
+ struct audio_capture_ops *ops,
+ void *cb_opaque
+ )
+{
+ CaptureVoiceOut *cap;
+ struct capture_callback *cb;
+
+ if (!s) {
+ /* XXX suppress */
+ s = &glob_audio_state;
+ }
+
+ if (audio_validate_settings (as)) {
+ dolog ("Invalid settings were passed when trying to add capture\n");
+ audio_print_settings (as);
+ goto err0;
+ }
+
+ cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
+ if (!cb) {
+ dolog ("Could not allocate capture callback information, size %zu\n",
+ sizeof (*cb));
+ goto err0;
+ }
+ cb->ops = *ops;
+ cb->opaque = cb_opaque;
+
+ cap = audio_pcm_capture_find_specific (s, as);
+ if (cap) {
+ LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
+ return cap;
+ }
+ else {
+ HWVoiceOut *hw;
+ CaptureVoiceOut *cap;
+
+ cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
+ if (!cap) {
+ dolog ("Could not allocate capture voice, size %zu\n",
+ sizeof (*cap));
+ goto err1;
+ }
+
+ hw = &cap->hw;
+ LIST_INIT (&hw->sw_head);
+ LIST_INIT (&cap->cb_head);
+
+ /* XXX find a more elegant way */
+ hw->samples = 4096 * 4;
+ hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
+ sizeof (st_sample_t));
+ if (!hw->mix_buf) {
+ dolog ("Could not allocate capture mix buffer (%d samples)\n",
+ hw->samples);
+ goto err2;
+ }
+
+ audio_pcm_init_info (&hw->info, as);
+
+ cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ if (!cap->buf) {
+ dolog ("Could not allocate capture buffer "
+ "(%d samples, each %d bytes)\n",
+ hw->samples, 1 << hw->info.shift);
+ goto err3;
+ }
+
+ hw->clip = mixeng_clip
+ [hw->info.nchannels == 2]
+ [hw->info.sign]
+ [hw->info.swap_endianness]
+ [hw->info.bits == 16];
+
+ LIST_INSERT_HEAD (&s->cap_head, cap, entries);
+ LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
+
+ hw = NULL;
+ while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
+ audio_attach_capture (s, hw);
+ }
+ return cap;
+
+ err3:
+ qemu_free (cap->hw.mix_buf);
+ err2:
+ qemu_free (cap);
+ err1:
+ qemu_free (cb);
+ err0:
+ return NULL;
+ }
+}
+
+void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
+{
+ struct capture_callback *cb;
+
+ for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
+ if (cb->opaque == cb_opaque) {
+ cb->ops.destroy (cb_opaque);
+ LIST_REMOVE (cb, entries);
+ qemu_free (cb);
+
+ if (!cap->cb_head.lh_first) {
+ SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
+
+ while (sw) {
+ SWVoiceCap *sc = (SWVoiceCap *) sw;
+#ifdef DEBUG_CAPTURE
+ dolog ("freeing %s\n", sw->name);
+#endif
+
+ sw1 = sw->entries.le_next;
+ if (sw->rate) {
+ st_rate_stop (sw->rate);
+ sw->rate = NULL;
+ }
+ LIST_REMOVE (sw, entries);
+ LIST_REMOVE (sc, entries);
+ qemu_free (sc);
+ sw = sw1;
+ }
+ LIST_REMOVE (cap, entries);
+ qemu_free (cap);
+ }
+ return;
+ }
+ }
+}
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
+#include "config.h"
#include "sys-queue.h"
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
AUD_FMT_S16
} audfmt_e;
+#ifdef WORDS_BIGENDIAN
+#define AUDIO_HOST_ENDIANNESS 1
+#else
+#define AUDIO_HOST_ENDIANNESS 0
+#endif
+
typedef struct {
int freq;
int nchannels;
audfmt_e fmt;
+ int endianness;
} audsettings_t;
+typedef enum {
+ AUD_CNOTIFY_ENABLE,
+ AUD_CNOTIFY_DISABLE
+} audcnotification_e;
+
+struct audio_capture_ops {
+ void (*notify) (void *opaque, audcnotification_e cmd);
+ void (*capture) (void *opaque, void *buf, int size);
+ void (*destroy) (void *opaque);
+};
+
+struct capture_ops {
+ void (*info) (void *opaque);
+ void (*destroy) (void *opaque);
+};
+
+typedef struct CaptureState {
+ void *opaque;
+ struct capture_ops ops;
+ LIST_ENTRY (CaptureState) entries;
+} CaptureState;
+
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
+typedef struct CaptureVoiceOut CaptureVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
void AUD_help (void);
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
+CaptureVoiceOut *AUD_add_capture (
+ AudioState *s,
+ audsettings_t *as,
+ struct audio_capture_ops *ops,
+ void *opaque
+ );
+void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
- audsettings_t *settings,
- int sw_endian
+ audsettings_t *settings
);
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
- audsettings_t *settings,
- int sw_endian
+ audsettings_t *settings
);
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
}
uint32_t popcount (uint32_t u);
-inline uint32_t lsbindex (uint32_t u);
+uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \
int align;
int shift;
int bytes_per_second;
- int swap_endian;
+ int swap_endianness;
};
+typedef struct SWVoiceCap SWVoiceCap;
+
typedef struct HWVoiceOut {
int enabled;
int pending_disable;
- int valid;
struct audio_pcm_info info;
f_sample *clip;
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
+ LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
+struct capture_callback {
+ struct audio_capture_ops ops;
+ void *opaque;
+ LIST_ENTRY (capture_callback) entries;
+};
+
+struct CaptureVoiceOut {
+ HWVoiceOut hw;
+ void *buf;
+ LIST_HEAD (cb_listhead, capture_callback) cb_head;
+ LIST_ENTRY (CaptureVoiceOut) entries;
+};
+
+struct SWVoiceCap {
+ SWVoiceOut sw;
+ CaptureVoiceOut *cap;
+ LIST_ENTRY (SWVoiceCap) entries;
+};
+
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
QEMUTimer *ts;
- LIST_HEAD (card_head, QEMUSoundCard) card_head;
+ LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
+ LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
int nb_hw_voices_out;
int nb_hw_voices_in;
};
extern struct audio_driver dsound_audio_driver;
extern volume_t nominal_volume;
-void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
- int swap_endian);
+void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
return (dst >= src) ? (dst - src) : (len - src + dst);
}
-static inline int audio_need_to_swap_endian (int endianness)
-{
-#ifdef WORDS_BIGENDIAN
- return endianness != 1;
-#else
- return endianness != 0;
-#endif
-}
-
#if defined __GNUC__
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
#define INIT_FIELD(f) . f
SW *sw,
HW *hw,
const char *name,
- audsettings_t *as,
- int endian
+ audsettings_t *as
)
{
int err;
- audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian));
+ audio_pcm_init_info (&sw->info, as);
sw->hw = hw;
sw->active = 0;
#ifdef DAC
#endif
[sw->info.nchannels == 2]
[sw->info.sign]
- [sw->info.swap_endian]
+ [sw->info.swap_endianness]
[sw->info.bits == 16];
sw->name = qemu_strdup (name);
HW *hw = *hwp;
if (!hw->sw_head.lh_first) {
+#ifdef DAC
+ audio_detach_capture (hw);
+#endif
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
-
+#ifdef DAC
+ LIST_INIT (&hw->cap_head);
+#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
}
#endif
[hw->info.nchannels == 2]
[hw->info.sign]
- [hw->info.swap_endian]
+ [hw->info.swap_endianness]
[hw->info.bits == 16];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
+#ifdef DAC
+ audio_attach_capture (s, hw);
+#endif
return hw;
err1:
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
AudioState *s,
const char *sw_name,
- audsettings_t *as,
- int sw_endian
+ audsettings_t *as
)
{
SW *sw;
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
- if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
+ if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
goto err3;
}
const char *name,
void *callback_opaque ,
audio_callback_fn_t callback_fn,
- audsettings_t *as,
- int sw_endian
+ audsettings_t *as
)
{
AudioState *s;
s = card->audio;
- if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
+ if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
audio_print_settings (as);
goto fail;
}
}
glue (audio_pcm_sw_fini_, TYPE) (sw);
- if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
+ if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
goto fail;
}
}
else {
- sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian);
+ sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
if (!sw) {
dolog ("Failed to create voice `%s'\n", name);
return NULL;
#endif
}
- /* cleanup */
- mixeng_clear (src, frameCount);
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
core->rpos = rpos;
UInt32 propertySize;
int err;
int bits = 8;
- int endianess = 0;
const char *typ = "playback";
AudioValueRange frameRange;
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
bits = 16;
- endianess = 1;
}
- audio_pcm_init_info (
- &hw->info,
- as,
- /* Following is irrelevant actually since we do not use
- mixengs clipping routines */
- audio_need_to_swap_endian (endianess)
- );
+ audio_pcm_init_info (&hw->info, as);
/* open default output device */
propertySize = sizeof(core->outputDeviceID);
int i;
LPVOID p1 = NULL, p2 = NULL;
DWORD blen1 = 0, blen2 = 0;
+ DWORD flag;
+#ifdef DSBTYPE_IN
+ flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
+#else
+ flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
+#endif
for (i = 0; i < conf.lock_retries; ++i) {
hr = glue (IFACE, _Lock) (
buf,
&blen1,
&p2,
&blen2,
- (entire
-#ifdef DSBTYPE_IN
- ? DSCBLOCK_ENTIREBUFFER
-#else
- ? DSBLOCK_ENTIREBUFFER
-#endif
- : 0)
+ flag
);
if (FAILED (hr)) {
}
ds->first_time = 1;
-
- audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
+ obt_as.endianness = 0;
+ audio_pcm_init_info (&hw->info, &obt_as);
if (bc.dwBufferBytes & hw->info.align) {
dolog (
if (src_len1) {
hw->clip (dst, src1, src_len1);
- mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
- mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
hr = IDirectSound_Initialize (s->dsound, NULL);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize DirectSound\n");
+
+ hr = IDirectSound_Release (s->dsound);
+ if (FAILED (hr)) {
+ dsound_logerr (hr, "Could not release DirectSound\n");
+ }
+ s->dsound = NULL;
return NULL;
}
if (src_len1) {
hw->clip (dst, src1, src_len1);
- mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
- mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
{
int bits16, mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+ audsettings_t obt_as = *as;
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
fmd->channel = channel;
/* FMOD always operates on little endian frames? */
- audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
+ obt_as.endianness = 0;
+ audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
{
int bits16, mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+ audsettings_t obt_as = *as;
if (conf.broken_adc) {
return -1;
}
/* FMOD always operates on little endian frames? */
- audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
+ obt_as.endianness = 0;
+ audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int live, decr, samples;
- int64_t now = qemu_get_clock (vm_clock);
- int64_t ticks = now - no->old_ticks;
- int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
-
- if (bytes > INT_MAX) {
- samples = INT_MAX >> hw->info.shift;
- }
- else {
- samples = bytes >> hw->info.shift;
- }
+ int64_t now;
+ int64_t ticks;
+ int64_t bytes;
live = audio_pcm_hw_get_live_out (&no->hw);
if (!live) {
return 0;
}
+ now = qemu_get_clock (vm_clock);
+ ticks = now - no->old_ticks;
+ bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
+ bytes = audio_MIN (bytes, INT_MAX);
+ samples = bytes >> hw->info.shift;
+
no->old_ticks = now;
decr = audio_MIN (live, samples);
hw->rpos = (hw->rpos + decr) % hw->samples;
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
{
- audio_pcm_init_info (&hw->info, as, 0);
+ audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
{
- audio_pcm_init_info (&hw->info, as, 0);
+ audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
static int no_run_in (HWVoiceIn *hw)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
- int64_t now = qemu_get_clock (vm_clock);
- int64_t ticks = now - no->old_ticks;
- int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
- int samples;
+ int samples = 0;
- bytes = audio_MIN (bytes, INT_MAX);
- samples = bytes >> hw->info.shift;
- samples = audio_MIN (samples, dead);
+ if (dead) {
+ int64_t now = qemu_get_clock (vm_clock);
+ int64_t ticks = now - no->old_ticks;
+ int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
+ no->old_ticks = now;
+ bytes = audio_MIN (bytes, INT_MAX);
+ samples = bytes >> hw->info.shift;
+ samples = audio_MIN (samples, dead);
+ }
return samples;
}
int fragsize;
const char *devpath_out;
const char *devpath_in;
+ int debug;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
- .devpath_in = "/dev/dsp"
+ .devpath_in = "/dev/dsp",
+ .debug = 0
};
struct oss_params {
return 0;
}
- if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
- ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
- abinfo.bytes, bufsize);
+ if (abinfo.bytes > bufsize) {
+ if (conf.debug) {
+ dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
+ "please report your OS/audio hw to malc@pulsesoft.com\n",
+ abinfo.bytes, bufsize);
+ }
+ abinfo.bytes = bufsize;
+ }
+
+ if (abinfo.bytes < 0) {
+ if (conf.debug) {
+ dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
+ abinfo.bytes, bufsize);
+ }
return 0;
}
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
- mixeng_clear (src, wsamples);
decr -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
- mixeng_clear (src, convert_samples);
-
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
+ obt_as.endianness = endianness;
- audio_pcm_init_info (
- &hw->info,
- &obt_as,
- audio_need_to_swap_endian (endianness)
- );
+ audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
+ obt_as.endianness = endianness;
- audio_pcm_init_info (
- &hw->info,
- &obt_as,
- audio_need_to_swap_endian (endianness)
- );
+ audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
"Path to DAC device", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
"Path to ADC device", NULL, 0},
+ {"DEBUG", AUD_OPT_BOOL, &conf.debug,
+ "Turn on some debugging messages", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
if (rate->opos_inc == (1ULL + UINT_MAX)) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
- OP (obuf[i].l, ibuf[i].r);
+ OP (obuf[i].l, ibuf[i].l);
OP (obuf[i].r, ibuf[i].r);
}
*isamp = n;
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
- mixeng_clear (src, chunk);
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
obt_as.freq = obt.freq;
obt_as.nchannels = obt.channels;
obt_as.fmt = effective_fmt;
+ obt_as.endianness = endianess;
- audio_pcm_init_info (
- &hw->info,
- &obt_as,
- audio_need_to_swap_endian (endianess)
- );
+ audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
s->initialized = 1;
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
- mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
hdr[34] = bits16 ? 0x10 : 0x08;
- audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0));
+ wav_as.endianness = 0;
+ audio_pcm_init_info (&hw->info, &wav_as);
hw->samples = 1024;
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
--- /dev/null
+#include "vl.h"
+
+typedef struct {
+ QEMUFile *f;
+ int bytes;
+ char *path;
+ int freq;
+ int bits;
+ int nchannels;
+ CaptureVoiceOut *cap;
+} WAVState;
+
+/* VICE code: Store number as little endian. */
+static void le_store (uint8_t *buf, uint32_t val, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ buf[i] = (uint8_t) (val & 0xff);
+ val >>= 8;
+ }
+}
+
+static void wav_notify (void *opaque, audcnotification_e cmd)
+{
+ (void) opaque;
+ (void) cmd;
+}
+
+static void wav_destroy (void *opaque)
+{
+ WAVState *wav = opaque;
+ uint8_t rlen[4];
+ uint8_t dlen[4];
+ uint32_t datalen = wav->bytes;
+ uint32_t rifflen = datalen + 36;
+
+ if (!wav->f) {
+ return;
+ }
+
+ le_store (rlen, rifflen, 4);
+ le_store (dlen, datalen, 4);
+
+ qemu_fseek (wav->f, 4, SEEK_SET);
+ qemu_put_buffer (wav->f, rlen, 4);
+
+ qemu_fseek (wav->f, 32, SEEK_CUR);
+ qemu_put_buffer (wav->f, dlen, 4);
+ fclose (wav->f);
+ if (wav->path) {
+ qemu_free (wav->path);
+ }
+}
+
+static void wav_capture (void *opaque, void *buf, int size)
+{
+ WAVState *wav = opaque;
+
+ qemu_put_buffer (wav->f, buf, size);
+ wav->bytes += size;
+}
+
+static void wav_capture_destroy (void *opaque)
+{
+ WAVState *wav = opaque;
+
+ AUD_del_capture (wav->cap, wav);
+}
+
+static void wav_capture_info (void *opaque)
+{
+ WAVState *wav = opaque;
+ char *path = wav->path;
+
+ term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
+ wav->freq, wav->bits, wav->nchannels,
+ path ? path : "<not available>", wav->bytes);
+}
+
+static struct capture_ops wav_capture_ops = {
+ .destroy = wav_capture_destroy,
+ .info = wav_capture_info
+};
+
+int wav_start_capture (CaptureState *s, const char *path, int freq,
+ int bits, int nchannels)
+{
+ WAVState *wav;
+ uint8_t hdr[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
+ 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
+ 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
+ };
+ audsettings_t as;
+ struct audio_capture_ops ops;
+ int stereo, bits16, shift;
+ CaptureVoiceOut *cap;
+
+ if (bits != 8 && bits != 16) {
+ term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
+ return -1;
+ }
+
+ if (nchannels != 1 && nchannels != 2) {
+ term_printf ("incorrect channel count %d, must be 1 or 2\n",
+ nchannels);
+ return -1;
+ }
+
+ stereo = nchannels == 2;
+ bits16 = bits == 16;
+
+ as.freq = freq;
+ as.nchannels = 1 << stereo;
+ as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
+ as.endianness = 0;
+
+ ops.notify = wav_notify;
+ ops.capture = wav_capture;
+ ops.destroy = wav_destroy;
+
+ wav = qemu_mallocz (sizeof (*wav));
+ if (!wav) {
+ term_printf ("Could not allocate memory for wav capture (%zu bytes)",
+ sizeof (*wav));
+ return -1;
+ }
+
+ shift = bits16 + stereo;
+ hdr[34] = bits16 ? 0x10 : 0x08;
+
+ le_store (hdr + 22, as.nchannels, 2);
+ le_store (hdr + 24, freq, 4);
+ le_store (hdr + 28, freq << shift, 4);
+ le_store (hdr + 32, 1 << shift, 2);
+
+ wav->f = fopen (path, "wb");
+ if (!wav->f) {
+ term_printf ("Failed to open wave file `%s'\nReason: %s\n",
+ path, strerror (errno));
+ qemu_free (wav);
+ return -1;
+ }
+
+ wav->path = qemu_strdup (path);
+ wav->bits = bits;
+ wav->nchannels = nchannels;
+ wav->freq = freq;
+
+ qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+
+ cap = AUD_add_capture (NULL, &as, &ops, wav);
+ if (!cap) {
+ term_printf ("Failed to add audio capture\n");
+ qemu_free (wav);
+ return -1;
+ }
+
+ wav->cap = cap;
+ s->opaque = wav;
+ s->ops = wav_capture_ops;
+ return 0;
+}
return 0;
}
+static void cow_flush(BlockDriverState *bs)
+{
+ BDRVCowState *s = bs->opaque;
+ fsync(s->fd);
+}
+
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
cow_write,
cow_close,
cow_create,
+ cow_flush,
cow_is_allocated,
};
#endif
return 0;
}
+static void qcow_flush(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ fsync(s->fd);
+}
+
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
qcow_write,
qcow_close,
qcow_create,
+ qcow_flush,
qcow_is_allocated,
qcow_set_key,
qcow_make_empty
close(s->fd);
}
+static void vmdk_flush(BlockDriverState *bs)
+{
+ BDRVVmdkState *s = bs->opaque;
+ fsync(s->fd);
+}
+
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
vmdk_write,
vmdk_close,
vmdk_create,
+ vmdk_flush,
vmdk_is_allocated,
};
bitmap_offset = 512 * s->pagetable[pagetable_index];
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
-// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
+// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
vvfat_read,
vvfat_write,
vvfat_close,
+ NULL, /* ??? Not sure if we can do any meaningful flushing. */
NULL,
vvfat_is_allocated
};
return bs->device_name;
}
+void bdrv_flush(BlockDriverState *bs)
+{
+ if (bs->drv->bdrv_flush)
+ bs->drv->bdrv_flush(bs);
+ if (bs->backing_hd)
+ bdrv_flush(bs->backing_hd);
+}
+
void bdrv_info(void)
{
BlockDriverState *bs;
close(s->fd);
}
+#ifdef _WIN32
+#include <windows.h>
+#include <winioctl.h>
+
+int qemu_ftruncate64(int fd, int64_t length)
+{
+ LARGE_INTEGER li;
+ LONG high;
+ HANDLE h;
+ BOOL res;
+
+ if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
+ return -1;
+
+ h = (HANDLE)_get_osfhandle(fd);
+
+ /* get current position, ftruncate do not change position */
+ li.HighPart = 0;
+ li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
+ if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+ return -1;
+
+ high = length >> 32;
+ if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
+ return -1;
+ res = SetEndOfFile(h);
+
+ /* back to old position */
+ SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
+ return res ? 0 : -1;
+}
+
+static int set_sparse(int fd)
+{
+ DWORD returned;
+ return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
+ NULL, 0, NULL, 0, &returned, NULL);
+}
+#else
+static inline int set_sparse(int fd)
+{
+ return 1;
+}
+#endif
+
static int raw_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
0644);
if (fd < 0)
return -EIO;
+ set_sparse(fd);
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
+static void raw_flush(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ fsync(s->fd);
+}
+
BlockDriver bdrv_raw = {
"raw",
sizeof(BDRVRawState),
raw_write,
raw_close,
raw_create,
+ raw_flush,
};
void bdrv_init(void)
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
+ void (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
/* handle monitor key events */
} else {
+ int keysym = 0;
+
switch([event keyCode]) {
- case 123:
- kbd_put_keysym(QEMU_KEY_LEFT);
- break;
- case 124:
- kbd_put_keysym(QEMU_KEY_RIGHT);
- break;
- case 125:
- kbd_put_keysym(QEMU_KEY_DOWN);
- break;
- case 126:
- kbd_put_keysym(QEMU_KEY_UP);
- break;
- default:
- kbd_put_keysym([[event characters] characterAtIndex:0]);
- break;
+ case 115:
+ keysym = QEMU_KEY_HOME;
+ break;
+ case 117:
+ keysym = QEMU_KEY_DELETE;
+ break;
+ case 119:
+ keysym = QEMU_KEY_END;
+ break;
+ case 123:
+ keysym = QEMU_KEY_LEFT;
+ break;
+ case 124:
+ keysym = QEMU_KEY_RIGHT;
+ break;
+ case 125:
+ keysym = QEMU_KEY_DOWN;
+ break;
+ case 126:
+ keysym = QEMU_KEY_UP;
+ break;
+ default:
+ {
+ NSString *ks = [event characters];
+
+ if ([ks length] > 0)
+ keysym = [ks characterAtIndex:0];
+ }
}
+ if (keysym)
+ kbd_put_keysym(keysym);
}
}
}
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
-
}
-static void CustomApplicationMain (argc, argv)
+static void CustomApplicationMain(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QemuCocoaGUIController *gui_controller;
{
gArgc = argc;
gArgv = argv;
-
- CustomApplicationMain (argc, argv);
-
+
+ CustomApplicationMain();
+
return 0;
}
softmmu="yes"
user="no"
build_docs="no"
+build_acpi_tables="no"
+uname_release=""
# OS specific
targetos=`uname -s`
;;
--fmod-inc=*) fmod_inc="$optarg"
;;
- --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
+ --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
;;
--disable-slirp) slirp="no"
;;
;;
--enable-user) user="yes"
;;
+ --enable-uname-release=*) uname_release="$optarg"
+ ;;
+ --enable-iasl) build_acpi_tables="yes"
+ ;;
esac
done
echo " --disable-user disable all linux usermode emulation targets"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
+echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo " --enable-iasl compilation of ACPI tables with the IASL compiler"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
-if [ ! -x "`which $cc`" ] ; then
- echo "Compiler $cc could not be found"
- exit
+# check that the C compiler works.
+cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
+ : C compiler works ok
+else
+ echo "ERROR: \"$cc\" either does not exist or does not work"
+ exit 1
fi
if test "$mingw32" = "yes" ; then
linux="no"
EXESUF=".exe"
- gdbstub="no"
oss="no"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
echo "FMOD support $fmod $fmod_support"
echo "kqemu support $kqemu"
echo "Documentation $build_docs"
+[ ! -z "$uname_release" ] && \
+echo "uname -r $uname_release"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
if [ "$build_docs" = "yes" ] ; then
echo "BUILD_DOCS=yes" >> $config_mak
fi
+if [ "$build_acpi_tables" = "yes" ] ; then
+ echo "BUILD_ACPI_TABLES=yes" >> $config_mak
+fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "#define _BSD 1" >> $config_h
fi
+echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
+
for target in $target_list; do
target_dir="$target"
config_mak=$target_dir/config.mak
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
+[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
echo "include ../config-host.mak" >> $config_mak
echo "#include \"../config-host.h\"" >> $config_h
+bflt="no"
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
+ bflt="yes"
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
echo "TARGET_ARCH=mips" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
-elif test "$target_cpu" = "sh4" ; then
+ echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
+ echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
echo "TARGET_ARCH=sh4" >> $config_mak
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
echo "#define TARGET_SH4 1" >> $config_h
+ bflt="yes"
else
echo "Unsupported target CPU"
exit 1
echo "#define CONFIG_DM 1" >> $config_h
fi
-if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
+if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
fi
+if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
+ echo "TARGET_HAS_BFLT=yes" >> $config_mak
+ echo "#define TARGET_HAS_BFLT 1" >> $config_h
+fi
# sdl defines
if test "$target_user_only" = "no"; then
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
-#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define RGB(r, g, b) RGBA(r, g, b, 0xff)
+#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
typedef struct TextAttributes {
uint8_t fgcol:4;
TTY_STATE_CSI,
};
+typedef struct QEMUFIFO {
+ uint8_t *buf;
+ int buf_size;
+ int count, wptr, rptr;
+} QEMUFIFO;
+
+int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
+{
+ int l, len;
+
+ l = f->buf_size - f->count;
+ if (len1 > l)
+ len1 = l;
+ len = len1;
+ while (len > 0) {
+ l = f->buf_size - f->wptr;
+ if (l > len)
+ l = len;
+ memcpy(f->buf + f->wptr, buf, l);
+ f->wptr += l;
+ if (f->wptr >= f->buf_size)
+ f->wptr = 0;
+ buf += l;
+ len -= l;
+ }
+ f->count += len1;
+ return len1;
+}
+
+int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
+{
+ int l, len;
+
+ if (len1 > f->count)
+ len1 = f->count;
+ len = len1;
+ while (len > 0) {
+ l = f->buf_size - f->rptr;
+ if (l > len)
+ l = len;
+ memcpy(buf, f->buf + f->rptr, l);
+ f->rptr += l;
+ if (f->rptr >= f->buf_size)
+ f->rptr = 0;
+ buf += l;
+ len -= l;
+ }
+ f->count -= len1;
+ return len1;
+}
+
/* ??? This is mis-named.
It is used for both text and graphical consoles. */
struct TextConsole {
int nb_esc_params;
/* kbd read handler */
+ IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
+ /* fifo for key pressed */
+ QEMUFIFO out_fifo;
+ uint8_t out_fifo_buf[16];
+ QEMUTimer *kbd_timer;
};
static TextConsole *active_console;
static const uint32_t color_table_rgb[2][8] = {
{ /* dark */
- RGB(0x00, 0x00, 0x00), /* black */
- RGB(0xaa, 0x00, 0x00), /* red */
- RGB(0x00, 0xaa, 0x00), /* green */
- RGB(0xaa, 0xaa, 0x00), /* yellow */
- RGB(0x00, 0x00, 0xaa), /* blue */
- RGB(0xaa, 0x00, 0xaa), /* magenta */
- RGB(0x00, 0xaa, 0xaa), /* cyan */
- RGB(0xaa, 0xaa, 0xaa), /* white */
+ QEMU_RGB(0x00, 0x00, 0x00), /* black */
+ QEMU_RGB(0xaa, 0x00, 0x00), /* red */
+ QEMU_RGB(0x00, 0xaa, 0x00), /* green */
+ QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
+ QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
+ QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
+ QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
+ QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
},
{ /* bright */
- RGB(0x00, 0x00, 0x00), /* black */
- RGB(0xff, 0x00, 0x00), /* red */
- RGB(0x00, 0xff, 0x00), /* green */
- RGB(0xff, 0xff, 0x00), /* yellow */
- RGB(0x00, 0x00, 0xff), /* blue */
- RGB(0xff, 0x00, 0xff), /* magenta */
- RGB(0x00, 0xff, 0xff), /* cyan */
- RGB(0xff, 0xff, 0xff), /* white */
+ QEMU_RGB(0x00, 0x00, 0x00), /* black */
+ QEMU_RGB(0xff, 0x00, 0x00), /* red */
+ QEMU_RGB(0x00, 0xff, 0x00), /* green */
+ QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
+ QEMU_RGB(0x00, 0x00, 0xff), /* blue */
+ QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
+ QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
+ QEMU_RGB(0xff, 0xff, 0xff), /* white */
}
};
TextCell *c;
int x, y1;
- s->x = 0;
s->y++;
if (s->y >= s->height) {
s->y = s->height - 1;
console_put_lf(s);
break;
case '\b': /* backspace */
- if(s->x > 0) s->x--;
- y1 = (s->y_base + s->y) % s->total_height;
- c = &s->cells[y1 * s->width + s->x];
- c->ch = ' ';
- c->t_attrib = s->t_attrib;
- update_xy(s, s->x, s->y);
+ if (s->x > 0)
+ s->x--;
break;
case '\t': /* tabspace */
if (s->x + (8 - (s->x % 8)) > s->width) {
+ s->x = 0;
console_put_lf(s);
} else {
s->x = s->x + (8 - (s->x % 8));
c->t_attrib = s->t_attrib;
update_xy(s, s->x, s->y);
s->x++;
- if (s->x >= s->width)
+ if (s->x >= s->width) {
+ s->x = 0;
console_put_lf(s);
+ }
break;
}
break;
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
+ s->fd_can_read = fd_can_read;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
}
}
+static void kbd_send_chars(void *opaque)
+{
+ TextConsole *s = opaque;
+ int len;
+ uint8_t buf[16];
+
+ len = s->fd_can_read(s->fd_opaque);
+ if (len > s->out_fifo.count)
+ len = s->out_fifo.count;
+ if (len > 0) {
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ qemu_fifo_read(&s->out_fifo, buf, len);
+ s->fd_read(s->fd_opaque, buf, len);
+ }
+ /* characters are pending: we send them a bit later (XXX:
+ horrible, should change char device API) */
+ if (s->out_fifo.count > 0) {
+ qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
+ }
+}
+
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
console_scroll(10);
break;
default:
- if (s->fd_read) {
- /* convert the QEMU keysym to VT100 key string */
- q = buf;
- if (keysym >= 0xe100 && keysym <= 0xe11f) {
- *q++ = '\033';
- *q++ = '[';
- c = keysym - 0xe100;
- if (c >= 10)
- *q++ = '0' + (c / 10);
- *q++ = '0' + (c % 10);
- *q++ = '~';
- } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
- *q++ = '\033';
- *q++ = '[';
- *q++ = keysym & 0xff;
- } else {
+ /* convert the QEMU keysym to VT100 key string */
+ q = buf;
+ if (keysym >= 0xe100 && keysym <= 0xe11f) {
+ *q++ = '\033';
+ *q++ = '[';
+ c = keysym - 0xe100;
+ if (c >= 10)
+ *q++ = '0' + (c / 10);
+ *q++ = '0' + (c % 10);
+ *q++ = '~';
+ } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
+ *q++ = '\033';
+ *q++ = '[';
+ *q++ = keysym & 0xff;
+ } else {
*q++ = keysym;
- }
- s->fd_read(s->fd_opaque, buf, q - buf);
+ }
+ if (s->fd_read) {
+ qemu_fifo_write(&s->out_fifo, buf, q - buf);
+ kbd_send_chars(s);
}
break;
}
chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
+ s->out_fifo.buf = s->out_fifo_buf;
+ s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
+ s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
+
if (!color_inited) {
color_inited = 1;
set_color_table(ds);
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
+/* acts like a ROM when read and like a device when written. As an
+ exception, the write memory callback gets the ram offset instead of
+ the physical address */
+#define IO_MEM_ROMD (1)
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
-/* profiling */
-#ifdef CONFIG_PROFILER
-static inline int64_t profile_getclock(void)
+/*******************************************/
+/* host CPU ticks (if available) */
+
+#if defined(__powerpc__)
+
+static inline uint32_t get_tbl(void)
+{
+ uint32_t tbl;
+ asm volatile("mftb %0" : "=r" (tbl));
+ return tbl;
+}
+
+static inline uint32_t get_tbu(void)
+{
+ uint32_t tbl;
+ asm volatile("mftbu %0" : "=r" (tbl));
+ return tbl;
+}
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ uint32_t l, h, h1;
+ /* NOTE: we test if wrapping has occurred */
+ do {
+ h = get_tbu();
+ l = get_tbl();
+ h1 = get_tbu();
+ } while (h != h1);
+ return ((int64_t)h << 32) | l;
+}
+
+#elif defined(__i386__)
+
+static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile ("rdtsc" : "=A" (val));
return val;
}
+#elif defined(__x86_64__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ uint32_t low,high;
+ int64_t val;
+ asm volatile("rdtsc" : "=a" (low), "=d" (high));
+ val = high;
+ val <<= 32;
+ val |= low;
+ return val;
+}
+
+#elif defined(__ia64)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ int64_t val;
+ asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
+ return val;
+}
+
+#elif defined(__s390__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+ int64_t val;
+ asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
+ return val;
+}
+
+#elif defined(__sparc_v9__)
+
+static inline int64_t cpu_get_real_ticks (void)
+{
+#if defined(_LP64)
+ uint64_t rval;
+ asm volatile("rd %%tick,%0" : "=r"(rval));
+ return rval;
+#else
+ union {
+ uint64_t i64;
+ struct {
+ uint32_t high;
+ uint32_t low;
+ } i32;
+ } rval;
+ asm volatile("rd %%tick,%1; srlx %1,32,%0"
+ : "=r"(rval.i32.high), "=r"(rval.i32.low));
+ return rval.i64;
+#endif
+}
+#endif
+
+/* profiling */
+#ifdef CONFIG_PROFILER
+static inline int64_t profile_getclock(void)
+{
+ return cpu_get_real_ticks();
+}
+
extern int64_t kqemu_time, kqemu_time_start;
extern int64_t qemu_time, qemu_time_start;
extern int64_t tlb_flush_time;
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
-#define TARGET_FMT_lx "%016llx"
+#define TARGET_FMT_lx "%016" PRIx64
#else
#error TARGET_LONG_SIZE undefined
#endif
longjmp(env->jmp_env, 1);
}
#endif
-#ifndef TARGET_SPARC
+#if !(defined(TARGET_SPARC) || defined(TARGET_SH4))
#define reg_T2
#endif
pc = env->regs[15];
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
- flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
+ // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
+ flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
+ | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
#else
- flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
+ // FPU enable . MMU enabled . MMU no-fault . Supervisor
+ flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
+ | env->psrs;
#endif
cs_base = env->npc;
pc = env->pc;
uint32_t *saved_regwptr;
#endif
#endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
int saved_i7, tmp_T0;
#endif
int ret, interrupt_request;
#if defined(reg_T2)
saved_T2 = T2;
#endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
#endif
T0 = 0; /* force lookup of first TB */
for(;;) {
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
do_interrupt(intno, 0, 0, 0, 1);
/* ensure that no TB jump will be modified as
the program flow was changed */
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
do_interrupt(env->interrupt_index);
env->interrupt_index = 0;
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#elif defined(TARGET_SH4)
/* XXXXX */
#endif
+ /* Don't use the cached interupt_request value,
+ do_interrupt may have updated the EXITTB flag. */
if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
lookup_symbol(tb->pc));
}
#endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. When the TB
"mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
- : "i0", "i1", "i2", "i3", "i4", "i5");
+ : "i0", "i1", "i2", "i3", "i4", "i5",
+ "l0", "l1", "l2", "l3", "l4", "l5",
+ "l6", "l7");
#elif defined(__arm__)
asm volatile ("mov pc, %0\n\t"
".global exec_loop\n\t"
#else
#error unsupported target CPU
#endif
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
#endif
T0 = saved_T0;
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
- if (ret == 1) {
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
- sigprocmask(SIG_SETMASK, old_set, NULL);
- // do_raise_exception_err(env->exception_index, env->error_code);
- } else {
- /* activate soft MMU for this block */
- cpu_resume_from_signal(env, puc);
- }
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
/* never comes here */
return 1;
}
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
- "Address 0x%llx is out of bounds.\n", memaddr);
+ "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
bfd_vma addr;
struct disassemble_info *info;
{
- (*info->fprintf_func) (info->stream, "0x%llx", addr);
+ (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
}
/* Just return the given address. */
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
+// Linux/Sparc64 defines uint64_t
+#if !(defined (__sparc_v9__) && defined(__linux__))
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__) || defined(__ia64)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
+#endif
/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
prior to this and will cause an error in compliation, conflicting
#endif
typedef signed short int16_t;
typedef signed int int32_t;
+// Linux/Sparc64 defines int64_t
+#if !(defined (__sparc_v9__) && defined(__linux__))
#if defined (__x86_64__) || defined(__ia64)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
#endif
+#endif
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define AREG3 "s2"
#endif
#ifdef __sparc__
+#ifdef HOST_SOLARIS
+#define AREG0 "g2"
+#define AREG1 "g3"
+#define AREG2 "g4"
+#define AREG3 "g5"
+#define AREG4 "g6"
+#else
+#ifdef __sparc_v9__
+#define AREG0 "g1"
+#define AREG1 "g4"
+#define AREG2 "g5"
+#define AREG3 "g7"
+#else
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
#define AREG9 "l5"
#define AREG10 "l6"
#define AREG11 "l7"
+#endif
+#endif
#define USE_FP_CONVERT
#endif
#ifdef __s390__
ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __sparc__
-#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
- "nop")
-#define GOTO_LABEL_PARAM(n) asm volatile ( \
- "set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop")
+#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
+#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
#endif
#ifdef __arm__
#define EXIT_TB() asm volatile ("b exec_loop")
} else {
#ifdef HOST_SPARC
if (sym_name[0] == '.')
- snprintf(name, sizeof(name),
+ snprintf(name, name_size,
"(long)(&__dot_%s)",
sym_name + 1);
else
}
#elif defined(HOST_SPARC)
{
+#define INSN_SAVE 0x9de3a000
+#define INSN_RET 0x81c7e008
+#define INSN_RETL 0x81c3e008
+#define INSN_RESTORE 0x81e80000
+#define INSN_RETURN 0x81cfe008
+#define INSN_NOP 0x01000000
+#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
+#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
+
uint32_t start_insn, end_insn1, end_insn2;
uint8_t *p;
p = (void *)(p_end - 8);
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
- if ((start_insn & ~0x1fff) == 0x9de3a000) {
+ if (((start_insn & ~0x1fff) == INSN_SAVE) ||
+ (start_insn & ~0x1fff) == INSN_ADD_SP) {
p_start += 0x4;
start_offset += 0x4;
- if ((int)(start_insn | ~0x1fff) < -128)
- error("Found bogus save at the start of %s", name);
- if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
+ if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
+ /* SPARC v7: ret; restore; */ ;
+ else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
+ /* SPARC v9: return; nop; */ ;
+ else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
+ /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
+ else
+
error("ret; restore; not found at end of %s", name);
+ } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
+ ;
} else {
error("No save at the beginning of %s", name);
}
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
- if (skip_insn == 0x01000000)
+ if (skip_insn == INSN_NOP)
p -= 4;
}
#endif
}
#elif defined(HOST_SPARC64)
{
+#define INSN_SAVE 0x9de3a000
+#define INSN_RET 0x81c7e008
+#define INSN_RETL 0x81c3e008
+#define INSN_RESTORE 0x81e80000
+#define INSN_RETURN 0x81cfe008
+#define INSN_NOP 0x01000000
+#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
+#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
+
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint8_t *p;
p = (void *)(p_end - 8);
+#if 0
+ /* XXX: check why it occurs */
if (p <= p_start)
error("empty code for %s", name);
+#endif
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
- if ((start_insn & ~0x1fff) == 0x9de3a000) {
+ if (((start_insn & ~0x1fff) == INSN_SAVE) ||
+ (start_insn & ~0x1fff) == INSN_ADD_SP) {
p_start += 0x4;
start_offset += 0x4;
- if ((int)(start_insn | ~0x1fff) < -256)
- error("Found bogus save at the start of %s", name);
- if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
+ if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
+ /* SPARC v7: ret; restore; */ ;
+ else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
+ /* SPARC v9: return; nop; */ ;
+ else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
+ /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
+ else
+
error("ret; restore; not found at end of %s", name);
+ } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
+ ;
} else {
error("No save at the beginning of %s", name);
}
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
+ case R_SPARC_WDISP22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffff) "
+ " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
+ " & 0x3fffff);\n",
+ rel->r_offset - start_offset,
+ rel->r_offset - start_offset,
+ name, addend,
+ rel->r_offset - start_offset);
+ break;
default:
error("unsupported sparc relocation (%d)", type);
}
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
- type = ELF64_R_TYPE(rel->r_info);
+ type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
break;
+ case R_SPARC_OLO10:
+ addend += ELF64_R_TYPE_DATA (rel->r_info);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3ff) "
+ " | ((%s + %d) & 0x3ff);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
case R_SPARC_WDISP30:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
+ case R_SPARC_WDISP22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x3fffff) "
+ " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
+ " & 0x3fffff);\n",
+ reloc_offset, reloc_offset, name, addend,
+ reloc_offset);
+ break;
default:
- error("unsupported sparc64 relocation (%d)", type);
+ error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
}
}
}
*/
int __op_param1, __op_param2, __op_param3;
-int __op_gen_label1, __op_gen_label2, __op_gen_label3;
+#ifdef __sparc__
+ void __op_gen_label1(){}
+ void __op_gen_label2(){}
+ void __op_gen_label3(){}
+#else
+ int __op_gen_label1, __op_gen_label2, __op_gen_label3;
+#endif
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
#define R_386_NONE 0
#define R_386_32 1
#define R_SPARC_10 30
#define R_SPARC_11 31
#define R_SPARC_64 32
+#define R_SPARC_OLO10 33
#define R_SPARC_WDISP16 40
#define R_SPARC_WDISP19 41
#define R_SPARC_7 43
ldub_code(addr);
}
pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
- if (pd > IO_MEM_ROM) {
+ if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
}
return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
if (is_softmmu)
#endif
{
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
/* IO memory case */
address = vaddr | pd;
addend = paddr;
te->addr_code = -1;
}
if (prot & PAGE_WRITE) {
- if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
- /* ROM: access is ignored (same as unassigned) */
- te->addr_write = vaddr | IO_MEM_ROM;
+ if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
+ (pd & IO_MEM_ROMD)) {
+ /* write access calls the I/O callback */
+ te->addr_write = vaddr |
+ (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
} else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
!cpu_physical_memory_is_dirty(pd)) {
te->addr_write = vaddr | IO_MEM_NOTDIRTY;
{
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
+ CPUState *env;
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + size;
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
p->phys_offset = phys_offset;
- if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
+ if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
+ (phys_offset & IO_MEM_ROMD))
phys_offset += TARGET_PAGE_SIZE;
}
+
+ /* since each CPU stores ram addresses in its TLB cache, we must
+ reset the modified entries */
+ /* XXX: slow ! */
+ for(env = first_cpu; env != NULL; env = env->next_cpu) {
+ tlb_flush(env, 1);
+ }
}
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
}
}
} else {
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+ !(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
if (l >= 4 && ((addr & 3) == 0)) {
}
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
- (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
+ (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
+ !(pd & IO_MEM_ROMD)) {
/* do nothing */
} else {
unsigned long addr1;
pd = p->phys_offset;
}
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+ !(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
pd = p->phys_offset;
}
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+ !(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
#ifdef TARGET_WORDS_BIGENDIAN
void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
-#if defined(_BSD) && !defined(__APPLE__)
+#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
fpsetround(val);
#elif defined(__arm__)
/* nothing to do */
}
#endif
-#if defined(_BSD)
-#define lrint(d) ((long)rint(d))
-#define llrint(d) ((long long)rint(d))
+#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
+#define lrint(d) ((int32_t)rint(d))
+#define llrint(d) ((int64_t)rint(d))
+#define lrintf(f) ((int32_t)rint(f))
+#define llrintf(f) ((int64_t)rint(f))
+#define sqrtf(f) ((float)sqrt(f))
+#define remainderf(fa, fb) ((float)remainder(fa, fb))
+#define rintf(f) ((float)rint(f))
#endif
#if defined(__powerpc__)
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "config.h"
#ifdef CONFIG_USER_ONLY
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <fcntl.h>
#include "qemu.h"
#else
#include "vl.h"
#endif
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
+#include "qemu_socket.h"
+#ifdef _WIN32
+/* XXX: these constants may be independent of the host ones even for Unix */
+#ifndef SIGTRAP
+#define SIGTRAP 5
+#endif
+#ifndef SIGINT
+#define SIGINT 2
+#endif
+#else
#include <signal.h>
+#endif
//#define DEBUG_GDB
int ret;
for(;;) {
- ret = read(s->fd, &ch, 1);
+ ret = recv(s->fd, &ch, 1, 0);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
int ret;
while (len > 0) {
- ret = write(s->fd, buf, len);
+ ret = send(s->fd, buf, len, 0);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
for(i = 0; i < 24; i++) {
registers[i + 8] = tswapl(env->regwptr[i]);
}
+#ifndef TARGET_SPARC64
/* fill in fprs */
for (i = 0; i < 32; i++) {
registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
}
-#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
registers[64] = tswapl(env->y);
{
registers[72] = 0;
return 73 * sizeof(target_ulong);
#else
- for (i = 0; i < 32; i += 2) {
- registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
+ /* fill in fprs */
+ for (i = 0; i < 64; i += 2) {
+ uint64_t tmp;
+
+ tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32;
+ tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1]));
+ registers[i/2 + 32] = tmp;
}
- registers[81] = tswapl(env->pc);
- registers[82] = tswapl(env->npc);
- registers[83] = tswapl(env->tstate[env->tl]);
- registers[84] = tswapl(env->fsr);
- registers[85] = tswapl(env->fprs);
- registers[86] = tswapl(env->y);
- return 87 * sizeof(target_ulong);
+ registers[64] = tswapl(env->pc);
+ registers[65] = tswapl(env->npc);
+ registers[66] = tswapl(env->tstate[env->tl]);
+ registers[67] = tswapl(env->fsr);
+ registers[68] = tswapl(env->fprs);
+ registers[69] = tswapl(env->y);
+ return 70 * sizeof(target_ulong);
#endif
}
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i + 8]);
}
+#ifndef TARGET_SPARC64
/* fill in fprs */
for (i = 0; i < 32; i++) {
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
}
-#ifndef TARGET_SPARC64
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
env->y = tswapl(registers[64]);
PUT_PSR(env, tswapl(registers[65]));
env->npc = tswapl(registers[69]);
env->fsr = tswapl(registers[70]);
#else
- for (i = 0; i < 32; i += 2) {
- uint64_t tmp;
- tmp = tswapl(registers[i/2 + 64]) << 32;
- tmp |= tswapl(registers[i/2 + 64 + 1]);
- *((uint64_t *)&env->fpr[i]) = tmp;
+ for (i = 0; i < 64; i += 2) {
+ *((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32);
+ *((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff);
}
- env->pc = tswapl(registers[81]);
- env->npc = tswapl(registers[82]);
- env->tstate[env->tl] = tswapl(registers[83]);
- env->fsr = tswapl(registers[84]);
- env->fprs = tswapl(registers[85]);
- env->y = tswapl(registers[86]);
+ env->pc = tswapl(registers[64]);
+ env->npc = tswapl(registers[65]);
+ env->tstate[env->tl] = tswapl(registers[66]);
+ env->fsr = tswapl(registers[67]);
+ env->fprs = tswapl(registers[68]);
+ env->y = tswapl(registers[69]);
#endif
}
#elif defined (TARGET_ARM)
int i;
#define SAVE(x) *ptr++=tswapl(x)
- for (i = 0; i < 16; i++) SAVE(env->gregs[i]);
+ if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+ for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
+ } else {
+ for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
+ }
+ for (i = 8; i < 16; i++) SAVE(env->gregs[i]);
SAVE (env->pc);
SAVE (env->pr);
SAVE (env->gbr);
int i;
#define LOAD(x) (x)=*ptr++;
- for (i = 0; i < 16; i++) LOAD(env->gregs[i]);
+ if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+ for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
+ } else {
+ for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
+ }
+ for (i = 8; i < 16; i++) LOAD(env->gregs[i]);
LOAD (env->pc);
LOAD (env->pr);
LOAD (env->gbr);
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
- uint32_t addr, len;
+ target_ulong addr, len;
#ifdef DEBUG_GDB
printf("command='%s'\n", line_buf);
break;
case 'c':
if (*p != '\0') {
- addr = strtoul(p, (char **)&p, 16);
+ addr = strtoull(p, (char **)&p, 16);
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
put_packet(s, "OK");
break;
case 'm':
- addr = strtoul(p, (char **)&p, 16);
+ addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
- len = strtoul(p, NULL, 16);
+ len = strtoull(p, NULL, 16);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) {
put_packet (s, "E14");
} else {
}
break;
case 'M':
- addr = strtoul(p, (char **)&p, 16);
+ addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
- len = strtoul(p, (char **)&p, 16);
+ len = strtoull(p, (char **)&p, 16);
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
- addr = strtoul(p, (char **)&p, 16);
+ addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
- len = strtoul(p, (char **)&p, 16);
+ len = strtoull(p, (char **)&p, 16);
if (type == 0 || type == 1) {
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
- addr = strtoul(p, (char **)&p, 16);
+ addr = strtoull(p, (char **)&p, 16);
if (*p == ',')
p++;
- len = strtoul(p, (char **)&p, 16);
+ len = strtoull(p, (char **)&p, 16);
if (type == 0 || type == 1) {
cpu_breakpoint_remove(env, addr);
put_packet(s, "OK");
goto breakpoint_error;
}
break;
+#ifdef CONFIG_USER_ONLY
+ case 'q':
+ if (strncmp(p, "Offsets", 7) == 0) {
+ TaskState *ts = env->opaque;
+
+ sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset,
+ ts->info->data_offset, ts->info->data_offset);
+ put_packet(s, buf);
+ break;
+ }
+ /* Fall through. */
+#endif
default:
// unknown_command:
/* put empty packet */
int i, size;
uint8_t buf[4096];
- size = read(s->fd, buf, sizeof(buf));
+ size = recv(s->fd, buf, sizeof(buf), 0);
if (size < 0)
return;
if (size == 0) {
/* set short latency */
val = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
s->env = first_cpu; /* XXX: allow to change CPU */
s->fd = fd;
+#ifdef CONFIG_USER_ONLY
fcntl(fd, F_SETFL, O_NONBLOCK);
+#else
+ socket_set_nonblock(fd);
-#ifndef CONFIG_USER_ONLY
/* stop the VM */
vm_stop(EXCP_INTERRUPT);
/* allow fast reuse */
val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
return -1;
}
#ifndef CONFIG_USER_ONLY
- fcntl(fd, F_SETFL, O_NONBLOCK);
+ socket_set_nonblock(fd);
#endif
return fd;
}
--- /dev/null
+/*
+ * QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+DefinitionBlock (
+ "acpi-dsdt.aml", // Output Filename
+ "DSDT", // Signature
+ 0x01, // DSDT Compliance Revision
+ "QEMU", // OEMID
+ "QEMUDSDT", // TABLE ID
+ 0x1 // OEM Revision
+ )
+{
+ Scope (\)
+ {
+ /* CMOS memory access */
+ OperationRegion (CMS, SystemIO, 0x70, 0x02)
+ Field (CMS, ByteAcc, NoLock, Preserve)
+ {
+ CMSI, 8,
+ CMSD, 8
+ }
+ Method (CMRD, 1, NotSerialized)
+ {
+ Store (Arg0, CMSI)
+ Store (CMSD, Local0)
+ Return (Local0)
+ }
+
+ /* Debug Output */
+ OperationRegion (DBG, SystemIO, 0xb044, 0x04)
+ Field (DBG, DWordAcc, NoLock, Preserve)
+ {
+ DBGL, 32,
+ }
+ }
+
+
+ /* PCI Bus definition */
+ Scope(\_SB) {
+ Device(PCI0) {
+ Name (_HID, EisaId ("PNP0A03"))
+ Name (_ADR, 0x00)
+ Name (_UID, 1)
+ Name(_PRT, Package() {
+ /* PCI IRQ routing table, example from ACPI 2.0a specification,
+ section 6.2.8.1 */
+ /* Note: we provide the same info as the PCI routing
+ table of the Bochs BIOS */
+
+ // PCI Slot 0
+ Package() {0x0000ffff, 0, LNKD, 0},
+ Package() {0x0000ffff, 1, LNKA, 0},
+ Package() {0x0000ffff, 2, LNKB, 0},
+ Package() {0x0000ffff, 3, LNKC, 0},
+
+ // PCI Slot 1
+ Package() {0x0001ffff, 0, LNKA, 0},
+ Package() {0x0001ffff, 1, LNKB, 0},
+ Package() {0x0001ffff, 2, LNKC, 0},
+ Package() {0x0001ffff, 3, LNKD, 0},
+
+ // PCI Slot 2
+ Package() {0x0002ffff, 0, LNKB, 0},
+ Package() {0x0002ffff, 1, LNKC, 0},
+ Package() {0x0002ffff, 2, LNKD, 0},
+ Package() {0x0002ffff, 3, LNKA, 0},
+
+ // PCI Slot 3
+ Package() {0x0003ffff, 0, LNKC, 0},
+ Package() {0x0003ffff, 1, LNKD, 0},
+ Package() {0x0003ffff, 2, LNKA, 0},
+ Package() {0x0003ffff, 3, LNKB, 0},
+
+ // PCI Slot 4
+ Package() {0x0004ffff, 0, LNKD, 0},
+ Package() {0x0004ffff, 1, LNKA, 0},
+ Package() {0x0004ffff, 2, LNKB, 0},
+ Package() {0x0004ffff, 3, LNKC, 0},
+
+ // PCI Slot 5
+ Package() {0x0005ffff, 0, LNKA, 0},
+ Package() {0x0005ffff, 1, LNKB, 0},
+ Package() {0x0005ffff, 2, LNKC, 0},
+ Package() {0x0005ffff, 3, LNKD, 0},
+ })
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (MEMP, ResourceTemplate ()
+ {
+ WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x00FF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0100, // Address Length
+ ,, )
+ IO (Decode16,
+ 0x0CF8, // Address Range Minimum
+ 0x0CF8, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x08, // Address Length
+ )
+ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x0CF7, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0CF8, // Address Length
+ ,, , TypeStatic)
+ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0D00, // Address Range Minimum
+ 0xFFFF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0xF300, // Address Length
+ ,, , TypeStatic)
+ DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x000A0000, // Address Range Minimum
+ 0x000BFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x00020000, // Address Length
+ ,, , AddressRangeMemory, TypeStatic)
+ DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x00000000, // Address Range Minimum
+ 0xFEBFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x00000000, // Address Length
+ ,, MEMF, AddressRangeMemory, TypeStatic)
+ })
+ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN)
+ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX)
+ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN)
+ /* compute available RAM */
+ Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0)
+ ShiftLeft(Local0, 16, Local0)
+ Add(Local0, 0x1000000, Local0)
+ /* update field of last region */
+ Store(Local0, PMIN)
+ Subtract (PMAX, PMIN, PLEN)
+ Increment (PLEN)
+ Return (MEMP)
+ }
+ }
+ }
+
+ Scope(\_SB.PCI0) {
+
+ /* PIIX3 ISA bridge */
+ Device (ISA) {
+ Name (_ADR, 0x00010000)
+
+ /* PIIX PCI to ISA irq remapping */
+ OperationRegion (P40C, PCI_Config, 0x60, 0x04)
+
+
+ /* Keyboard seems to be important for WinXP install */
+ Device (KBD)
+ {
+ Name (_HID, EisaId ("PNP0303"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0f)
+ }
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (TMP, ResourceTemplate ()
+ {
+ IO (Decode16,
+ 0x0060, // Address Range Minimum
+ 0x0060, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x01, // Address Length
+ )
+ IO (Decode16,
+ 0x0064, // Address Range Minimum
+ 0x0064, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x01, // Address Length
+ )
+ IRQNoFlags ()
+ {1}
+ })
+ Return (TMP)
+ }
+ }
+
+ /* PS/2 mouse */
+ Device (MOU)
+ {
+ Name (_HID, EisaId ("PNP0F13"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0f)
+ }
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (TMP, ResourceTemplate ()
+ {
+ IRQNoFlags () {12}
+ })
+ Return (TMP)
+ }
+ }
+
+ /* PS/2 floppy controller */
+ Device (FDC0)
+ {
+ Name (_HID, EisaId ("PNP0700"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+ IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+ IRQNoFlags () {6}
+ DMA (Compatibility, NotBusMaster, Transfer8) {2}
+ })
+ Return (BUF0)
+ }
+ }
+
+ /* Parallel port */
+ Device (LPT)
+ {
+ Name (_HID, EisaId ("PNP0400"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (\_SB.PCI0.PX13.DRSA, Local0)
+ And (Local0, 0x80000000, Local0)
+ If (LEqual (Local0, 0))
+ {
+ Return (0x00)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
+ IRQNoFlags () {7}
+ })
+ Return (BUF0)
+ }
+ }
+
+ /* Serial Ports */
+ Device (COM1)
+ {
+ Name (_HID, EisaId ("PNP0501"))
+ Name (_UID, 0x01)
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (\_SB.PCI0.PX13.DRSC, Local0)
+ And (Local0, 0x08000000, Local0)
+ If (LEqual (Local0, 0))
+ {
+ Return (0x00)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+ IRQNoFlags () {4}
+ })
+ Return (BUF0)
+ }
+ }
+
+ Device (COM2)
+ {
+ Name (_HID, EisaId ("PNP0501"))
+ Name (_UID, 0x02)
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (\_SB.PCI0.PX13.DRSC, Local0)
+ And (Local0, 0x80000000, Local0)
+ If (LEqual (Local0, 0))
+ {
+ Return (0x00)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+ IRQNoFlags () {3}
+ })
+ Return (BUF0)
+ }
+ }
+ }
+
+ /* PIIX4 PM */
+ Device (PX13) {
+ Name (_ADR, 0x00010003)
+
+ OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
+ Field (P13C, DWordAcc, NoLock, Preserve)
+ {
+ DRSA, 32,
+ DRSB, 32,
+ DRSC, 32,
+ DRSE, 32,
+ DRSF, 32,
+ DRSG, 32,
+ DRSH, 32,
+ DRSI, 32,
+ DRSJ, 32
+ }
+ }
+ }
+
+ /* PCI IRQs */
+ Scope(\_SB) {
+ Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
+ {
+ PRQ0, 8,
+ PRQ1, 8,
+ PRQ2, 8,
+ PRQ3, 8
+ }
+
+ Device(LNKA){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 1)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ0, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ0, 0x80, PRQ0)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ0, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ0)
+ }
+ }
+ Device(LNKB){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 2)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ1, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ1, 0x80, PRQ1)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ1, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ1)
+ }
+ }
+ Device(LNKC){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 3)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ2, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ2, 0x80, PRQ2)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ2, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ2)
+ }
+ }
+ Device(LNKD){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 4)
+ Name(_PRS, ResourceTemplate(){
+ IRQ (Level, ActiveLow, Shared)
+ {3,4,5,6,7,9,10,11,12}
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ3, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ3, 0x80, PRQ3)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ IRQ (Level, ActiveLow, Shared)
+ {1}
+ })
+ CreateWordField (PRR0, 0x01, TMP)
+ Store (PRQ3, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ ShiftLeft (One, Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateWordField (Arg0, 0x01, TMP)
+ FindSetRightBit (TMP, Local0)
+ Decrement (Local0)
+ Store (Local0, PRQ3)
+ }
+ }
+ }
+
+ /* S5 = power off state */
+ Name (_S5, Package (4) {
+ 0x00, // PM1a_CNT.SLP_TYP
+ 0x00, // PM2a_CNT.SLP_TYP
+ 0x00, // reserved
+ 0x00, // reserved
+ })
+}
--- /dev/null
+/*
+ *
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20060421 [Apr 29 2006]
+ * Copyright (C) 2000 - 2006 Intel Corporation
+ * Supports ACPI Specification Revision 3.0a
+ *
+ * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006
+ *
+ * C source code output
+ *
+ */
+unsigned char AmlCode[] =
+{
+ 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */
+ 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */
+ 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */
+ 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
+ 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */
+ 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */
+ 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */
+ 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */
+ 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */
+ 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */
+ 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */
+ 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */
+ 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */
+ 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */
+ 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */
+ 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */
+ 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */
+ 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */
+ 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */
+ 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */
+ 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */
+ 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */
+ 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */
+ 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */
+ 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */
+ 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */
+ 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */
+ 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */
+ 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */
+ 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */
+ 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */
+ 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */
+ 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */
+ 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */
+ 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */
+ 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */
+ 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */
+ 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */
+ 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */
+ 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */
+ 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */
+ 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */
+ 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */
+ 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */
+ 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */
+ 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */
+ 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */
+ 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */
+ 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */
+ 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */
+ 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */
+ 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */
+ 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */
+ 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */
+ 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */
+ 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */
+ 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */
+ 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */
+ 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */
+ 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */
+ 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */
+ 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */
+ 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */
+ 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */
+ 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */
+ 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */
+ 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */
+ 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */
+ 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */
+ 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */
+ 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */
+ 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */
+ 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */
+ 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */
+ 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */
+ 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */
+ 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */
+ 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */
+ 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */
+ 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */
+ 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */
+ 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */
+ 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */
+ 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */
+ 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */
+ 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */
+ 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */
+ 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */
+ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */
+ 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */
+ 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */
+ 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */
+ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */
+ 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */
+ 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */
+ 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */
+ 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */
+ 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */
+ 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */
+ 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */
+ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */
+ 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */
+ 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */
+ 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */
+ 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */
+ 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */
+ 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */
+ 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */
+ 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */
+ 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */
+ 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */
+ 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */
+ 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */
+ 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */
+ 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */
+ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */
+ 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */
+ 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */
+ 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */
+ 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */
+ 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */
+ 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */
+ 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */
+ 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */
+ 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */
+ 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */
+ 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */
+ 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */
+ 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */
+ 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */
+ 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */
+ 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */
+ 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */
+ 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */
+ 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */
+ 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */
+ 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */
+ 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */
+ 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */
+ 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */
+ 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */
+ 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */
+ 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */
+ 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */
+ 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */
+ 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */
+ 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */
+ 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */
+ 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */
+ 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */
+ 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */
+ 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */
+ 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */
+ 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */
+ 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */
+ 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */
+ 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */
+ 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */
+ 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */
+ 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */
+ 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */
+ 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */
+ 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */
+ 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */
+ 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */
+ 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */
+ 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */
+ 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */
+ 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */
+ 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */
+ 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */
+ 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */
+ 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */
+ 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */
+ 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */
+ 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */
+ 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */
+ 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */
+ 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */
+ 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */
+ 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */
+ 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */
+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */
+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */
+ 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */
+ 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */
+ 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */
+ 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */
+ 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */
+ 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */
+ 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */
+ 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */
+ 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */
+ 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */
+ 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */
+ 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */
+ 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */
+ 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */
+ 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */
+ 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */
+ 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */
+ 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */
+ 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */
+ 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */
+ 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */
+ 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */
+ 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */
+ 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */
+ 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */
+ 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */
+ 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */
+ 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */
+ 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */
+ 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */
+ 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */
+ 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */
+ 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */
+ 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */
+ 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */
+ 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */
+ 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */
+ 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */
+ 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */
+ 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */
+ 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */
+ 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */
+ 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */
+ 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */
+ 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */
+ 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */
+ 0x00,0x00,
+};
--- /dev/null
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "vl.h"
+
+//#define DEBUG
+
+/* i82731AB (PIIX4) compatible power management function */
+#define PM_FREQ 3579545
+
+/* XXX: make them variable */
+#define PM_IO_BASE 0xb000
+#define SMI_CMD_IO_ADDR 0xb040
+#define ACPI_DBG_IO_ADDR 0xb044
+
+typedef struct PIIX4PMState {
+ PCIDevice dev;
+ uint16_t pmsts;
+ uint16_t pmen;
+ uint16_t pmcntrl;
+ QEMUTimer *tmr_timer;
+ int64_t tmr_overflow_time;
+} PIIX4PMState;
+
+#define RTC_EN (1 << 10)
+#define PWRBTN_EN (1 << 8)
+#define GBL_EN (1 << 5)
+#define TMROF_EN (1 << 0)
+
+#define SCI_EN (1 << 0)
+
+#define SUS_EN (1 << 13)
+
+/* Note: only used for ACPI bios init. Could be deleted when ACPI init
+ is integrated in Bochs BIOS */
+static PIIX4PMState *piix4_pm_state;
+
+static uint32_t get_pmtmr(PIIX4PMState *s)
+{
+ uint32_t d;
+ d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
+ return d & 0xffffff;
+}
+
+static int get_pmsts(PIIX4PMState *s)
+{
+ int64_t d;
+ int pmsts;
+ pmsts = s->pmsts;
+ d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
+ if (d >= s->tmr_overflow_time)
+ s->pmsts |= TMROF_EN;
+ return pmsts;
+}
+
+static void pm_update_sci(PIIX4PMState *s)
+{
+ int sci_level, pmsts;
+ int64_t expire_time;
+
+ pmsts = get_pmsts(s);
+ sci_level = (((pmsts & s->pmen) &
+ (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
+ pci_set_irq(&s->dev, 0, sci_level);
+ /* schedule a timer interruption if needed */
+ if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
+ expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
+ qemu_mod_timer(s->tmr_timer, expire_time);
+ } else {
+ qemu_del_timer(s->tmr_timer);
+ }
+}
+
+static void pm_tmr_timer(void *opaque)
+{
+ PIIX4PMState *s = opaque;
+ pm_update_sci(s);
+}
+
+static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ PIIX4PMState *s = opaque;
+ addr &= 0x3f;
+ switch(addr) {
+ case 0x00:
+ {
+ int64_t d;
+ int pmsts;
+ pmsts = get_pmsts(s);
+ if (pmsts & val & TMROF_EN) {
+ /* if TMRSTS is reset, then compute the new overflow time */
+ d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
+ s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
+ }
+ s->pmsts &= ~val;
+ pm_update_sci(s);
+ }
+ break;
+ case 0x02:
+ s->pmen = val;
+ pm_update_sci(s);
+ break;
+ case 0x04:
+ {
+ int sus_typ;
+ s->pmcntrl = val & ~(SUS_EN);
+ if (val & SUS_EN) {
+ /* change suspend type */
+ sus_typ = (val >> 10) & 3;
+ switch(sus_typ) {
+ case 0: /* soft power off */
+ qemu_system_shutdown_request();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG
+ printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
+#endif
+}
+
+static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
+{
+ PIIX4PMState *s = opaque;
+ uint32_t val;
+
+ addr &= 0x3f;
+ switch(addr) {
+ case 0x00:
+ val = get_pmsts(s);
+ break;
+ case 0x02:
+ val = s->pmen;
+ break;
+ case 0x04:
+ val = s->pmcntrl;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+#ifdef DEBUG
+ printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
+#endif
+ return val;
+}
+
+static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ // PIIX4PMState *s = opaque;
+ addr &= 0x3f;
+#ifdef DEBUG
+ printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
+#endif
+}
+
+static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
+{
+ PIIX4PMState *s = opaque;
+ uint32_t val;
+
+ addr &= 0x3f;
+ switch(addr) {
+ case 0x08:
+ val = get_pmtmr(s);
+ break;
+ default:
+ val = 0;
+ break;
+ }
+#ifdef DEBUG
+ printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
+#endif
+ return val;
+}
+
+static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PIIX4PMState *s = opaque;
+#ifdef DEBUG
+ printf("SMI cmd val=0x%02x\n", val);
+#endif
+ switch(val) {
+ case 0xf0: /* ACPI disable */
+ s->pmcntrl &= ~SCI_EN;
+ break;
+ case 0xf1: /* ACPI enable */
+ s->pmcntrl |= SCI_EN;
+ break;
+ }
+}
+
+static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+#if defined(DEBUG)
+ printf("ACPI: DBG: 0x%08x\n", val);
+#endif
+}
+
+/* XXX: we still add it to the PIIX3 and we count on the fact that
+ OSes are smart enough to accept this strange configuration */
+void piix4_pm_init(PCIBus *bus, int devfn)
+{
+ PIIX4PMState *s;
+ uint8_t *pci_conf;
+ uint32_t pm_io_base;
+
+ s = (PIIX4PMState *)pci_register_device(bus,
+ "PM", sizeof(PIIX4PMState),
+ devfn, NULL, NULL);
+ pci_conf = s->dev.config;
+ pci_conf[0x00] = 0x86;
+ pci_conf[0x01] = 0x80;
+ pci_conf[0x02] = 0x13;
+ pci_conf[0x03] = 0x71;
+ pci_conf[0x08] = 0x00; // revision number
+ pci_conf[0x09] = 0x00;
+ pci_conf[0x0a] = 0x80; // other bridge device
+ pci_conf[0x0b] = 0x06; // bridge device
+ pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[0x3d] = 0x01; // interrupt pin 1
+
+ pm_io_base = PM_IO_BASE;
+ pci_conf[0x40] = pm_io_base | 1;
+ pci_conf[0x41] = pm_io_base >> 8;
+ register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
+ register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
+ register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
+ register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
+
+ register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s);
+ register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
+
+ /* XXX: which specification is used ? The i82731AB has different
+ mappings */
+ pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
+ pci_conf[0x63] = 0x60;
+ pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
+ (serial_hds[1] != NULL ? 0x90 : 0);
+
+ s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
+ piix4_pm_state = s;
+}
+
+/* ACPI tables */
+/* XXX: move them in the Bochs BIOS ? */
+
+/*************************************************/
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+ BSD license) */
+
+#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
+ uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
+ uint32_t length; /* Length of table, in bytes, including header */\
+ uint8_t revision; /* ACPI Specification minor version # */\
+ uint8_t checksum; /* To make sum of entire table == 0 */\
+ uint8_t oem_id [6]; /* OEM identification */\
+ uint8_t oem_table_id [8]; /* OEM table identification */\
+ uint32_t oem_revision; /* OEM revision number */\
+ uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
+ uint32_t asl_compiler_revision; /* ASL compiler revision number */
+
+
+struct acpi_table_header /* ACPI common table header */
+{
+ ACPI_TABLE_HEADER_DEF
+};
+
+struct rsdp_descriptor /* Root System Descriptor Pointer */
+{
+ uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
+ uint8_t checksum; /* To make sum of struct == 0 */
+ uint8_t oem_id [6]; /* OEM identification */
+ uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
+ uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
+ uint32_t length; /* XSDT Length in bytes including hdr */
+ uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
+ uint8_t extended_checksum; /* Checksum of entire table */
+ uint8_t reserved [3]; /* Reserved field must be 0 */
+};
+
+/*
+ * ACPI 1.0 Root System Description Table (RSDT)
+ */
+struct rsdt_descriptor_rev1
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ uint32_t table_offset_entry [2]; /* Array of pointers to other */
+ /* ACPI tables */
+};
+
+/*
+ * ACPI 1.0 Firmware ACPI Control Structure (FACS)
+ */
+struct facs_descriptor_rev1
+{
+ uint8_t signature[4]; /* ACPI Signature */
+ uint32_t length; /* Length of structure, in bytes */
+ uint32_t hardware_signature; /* Hardware configuration signature */
+ uint32_t firmware_waking_vector; /* ACPI OS waking vector */
+ uint32_t global_lock; /* Global Lock */
+ uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
+ uint32_t reserved1 : 31; /* Must be 0 */
+ uint8_t resverved3 [40]; /* Reserved - must be zero */
+};
+
+
+/*
+ * ACPI 1.0 Fixed ACPI Description Table (FADT)
+ */
+struct fadt_descriptor_rev1
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ uint32_t firmware_ctrl; /* Physical address of FACS */
+ uint32_t dsdt; /* Physical address of DSDT */
+ uint8_t model; /* System Interrupt Model */
+ uint8_t reserved1; /* Reserved */
+ uint16_t sci_int; /* System vector of SCI interrupt */
+ uint32_t smi_cmd; /* Port address of SMI command port */
+ uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
+ uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
+ uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
+ uint8_t reserved2; /* Reserved - must be zero */
+ uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
+ uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
+ uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
+ uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
+ uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
+ uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
+ uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
+ uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
+ uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
+ uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
+ uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
+ uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
+ uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
+ uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
+ uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
+ uint8_t reserved3; /* Reserved */
+ uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
+ uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
+ uint16_t flush_size; /* Size of area read to flush caches */
+ uint16_t flush_stride; /* Stride used in flushing caches */
+ uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
+ uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
+ uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
+ uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
+ uint8_t century; /* Index to century in RTC CMOS RAM */
+ uint8_t reserved4; /* Reserved */
+ uint8_t reserved4a; /* Reserved */
+ uint8_t reserved4b; /* Reserved */
+#if 0
+ uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
+ uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
+ uint32_t proc_c1 : 1; /* All processors support C1 state */
+ uint32_t plvl2_up : 1; /* C2 state works on MP system */
+ uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
+ uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
+ uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
+ uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
+ uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
+ uint32_t reserved5 : 23; /* Reserved - must be zero */
+#else
+ uint32_t flags;
+#endif
+};
+
+/*
+ * MADT values and structures
+ */
+
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC 0
+#define MULTIPLE_APIC 1
+
+
+/* Master MADT */
+
+struct multiple_apic_table
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ uint32_t local_apic_address; /* Physical address of local APIC */
+#if 0
+ uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
+ uint32_t reserved1 : 31;
+#else
+ uint32_t flags;
+#endif
+};
+
+
+/* Values for Type in APIC_HEADER_DEF */
+
+#define APIC_PROCESSOR 0
+#define APIC_IO 1
+#define APIC_XRUPT_OVERRIDE 2
+#define APIC_NMI 3
+#define APIC_LOCAL_NMI 4
+#define APIC_ADDRESS_OVERRIDE 5
+#define APIC_IO_SAPIC 6
+#define APIC_LOCAL_SAPIC 7
+#define APIC_XRUPT_SOURCE 8
+#define APIC_RESERVED 9 /* 9 and greater are reserved */
+
+/*
+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ */
+#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
+ uint8_t type; \
+ uint8_t length;
+
+/* Sub-structures for MADT */
+
+struct madt_processor_apic
+{
+ APIC_HEADER_DEF
+ uint8_t processor_id; /* ACPI processor id */
+ uint8_t local_apic_id; /* Processor's local APIC id */
+#if 0
+ uint32_t processor_enabled: 1; /* Processor is usable if set */
+ uint32_t reserved2 : 31; /* Reserved, must be zero */
+#else
+ uint32_t flags;
+#endif
+};
+
+struct madt_io_apic
+{
+ APIC_HEADER_DEF
+ uint8_t io_apic_id; /* I/O APIC ID */
+ uint8_t reserved; /* Reserved - must be zero */
+ uint32_t address; /* APIC physical address */
+ uint32_t interrupt; /* Global system interrupt where INTI
+ * lines start */
+};
+
+#include "acpi-dsdt.hex"
+
+static int acpi_checksum(const uint8_t *data, int len)
+{
+ int sum, i;
+ sum = 0;
+ for(i = 0; i < len; i++)
+ sum += data[i];
+ return (-sum) & 0xff;
+}
+
+static void acpi_build_table_header(struct acpi_table_header *h,
+ char *sig, int len)
+{
+ memcpy(h->signature, sig, 4);
+ h->length = cpu_to_le32(len);
+ h->revision = 0;
+ memcpy(h->oem_id, "QEMU ", 6);
+ memcpy(h->oem_table_id, "QEMU", 4);
+ memcpy(h->oem_table_id + 4, sig, 4);
+ h->oem_revision = cpu_to_le32(1);
+ memcpy(h->asl_compiler_id, "QEMU", 4);
+ h->asl_compiler_revision = cpu_to_le32(1);
+ h->checksum = acpi_checksum((void *)h, len);
+}
+
+#define ACPI_TABLES_BASE 0x000e8000
+
+/* base_addr must be a multiple of 4KB */
+void acpi_bios_init(void)
+{
+ struct rsdp_descriptor *rsdp;
+ struct rsdt_descriptor_rev1 *rsdt;
+ struct fadt_descriptor_rev1 *fadt;
+ struct facs_descriptor_rev1 *facs;
+ struct multiple_apic_table *madt;
+ uint8_t *dsdt;
+ uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr;
+ uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size;
+ int i;
+
+ /* compute PCI I/O addresses */
+ pm_io_base = (piix4_pm_state->dev.config[0x40] |
+ (piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f;
+
+ base_addr = ACPI_TABLES_BASE;
+
+ /* reserve memory space for tables */
+ addr = base_addr;
+ rsdp = (void *)(phys_ram_base + addr);
+ addr += sizeof(*rsdp);
+
+ rsdt_addr = addr;
+ rsdt = (void *)(phys_ram_base + addr);
+ addr += sizeof(*rsdt);
+
+ fadt_addr = addr;
+ fadt = (void *)(phys_ram_base + addr);
+ addr += sizeof(*fadt);
+
+ /* XXX: FACS should be in RAM */
+ addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
+ facs_addr = addr;
+ facs = (void *)(phys_ram_base + addr);
+ addr += sizeof(*facs);
+
+ dsdt_addr = addr;
+ dsdt = (void *)(phys_ram_base + addr);
+ addr += sizeof(AmlCode);
+
+ addr = (addr + 7) & ~7;
+ madt_addr = addr;
+ madt_size = sizeof(*madt) +
+ sizeof(struct madt_processor_apic) * smp_cpus +
+ sizeof(struct madt_io_apic);
+ madt = (void *)(phys_ram_base + addr);
+ addr += madt_size;
+
+ acpi_tables_size = addr - base_addr;
+
+ cpu_register_physical_memory(base_addr, acpi_tables_size,
+ base_addr | IO_MEM_ROM);
+
+ /* RSDP */
+ memset(rsdp, 0, sizeof(*rsdp));
+ memcpy(rsdp->signature, "RSD PTR ", 8);
+ memcpy(rsdp->oem_id, "QEMU ", 6);
+ rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
+ rsdp->checksum = acpi_checksum((void *)rsdp, 20);
+
+ /* RSDT */
+ rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
+ rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
+ acpi_build_table_header((struct acpi_table_header *)rsdt,
+ "RSDT", sizeof(*rsdt));
+
+ /* FADT */
+ memset(fadt, 0, sizeof(*fadt));
+ fadt->firmware_ctrl = cpu_to_le32(facs_addr);
+ fadt->dsdt = cpu_to_le32(dsdt_addr);
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+ fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]);
+ fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
+ fadt->acpi_enable = 0xf1;
+ fadt->acpi_disable = 0xf0;
+ fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
+ fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+ fadt->plvl2_lat = cpu_to_le16(50);
+ fadt->plvl3_lat = cpu_to_le16(50);
+ fadt->plvl3_lat = cpu_to_le16(50);
+ /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
+ fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
+ acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
+ sizeof(*fadt));
+
+ /* FACS */
+ memset(facs, 0, sizeof(*facs));
+ memcpy(facs->signature, "FACS", 4);
+ facs->length = cpu_to_le32(sizeof(*facs));
+
+ /* DSDT */
+ memcpy(dsdt, AmlCode, sizeof(AmlCode));
+
+ /* MADT */
+ {
+ struct madt_processor_apic *apic;
+ struct madt_io_apic *io_apic;
+
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(0xfee00000);
+ madt->flags = cpu_to_le32(1);
+ apic = (void *)(madt + 1);
+ for(i=0;i<smp_cpus;i++) {
+ apic->type = APIC_PROCESSOR;
+ apic->length = sizeof(*apic);
+ apic->processor_id = i;
+ apic->local_apic_id = i;
+ apic->flags = cpu_to_le32(1);
+ apic++;
+ }
+ io_apic = (void *)apic;
+ io_apic->type = APIC_IO;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->io_apic_id = smp_cpus;
+ io_apic->address = cpu_to_le32(0xfec00000);
+ io_apic->interrupt = cpu_to_le32(0);
+
+ acpi_build_table_header((struct acpi_table_header *)madt,
+ "APIC", madt_size);
+ }
+}
as.freq = conf.freq;
as.nchannels = SHIFT;
as.fmt = AUD_FMT_S16;
+ as.endianness = AUDIO_HOST_ENDIANNESS;
AUD_register_card (audio, "adlib", &s->card);
"adlib",
s,
adlib_callback,
- &as,
- 0 /* XXX: little endian? */
+ &as
);
if (!s->voice) {
Adlib_fini (s);
--- /dev/null
+/*
+ * QEMU Ultrasparc APB PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState APBState;
+
+static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ APBState *s = opaque;
+ int i;
+
+ for (i = 11; i < 32; i++) {
+ if ((val & (1 << i)) != 0)
+ break;
+ }
+ s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
+}
+
+static uint32_t pci_apb_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ APBState *s = opaque;
+ uint32_t val;
+ int devfn;
+
+ devfn = (s->config_reg >> 8) & 0xFF;
+ val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_apb_config_write[] = {
+ &pci_apb_config_writel,
+ &pci_apb_config_writel,
+ &pci_apb_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_apb_config_read[] = {
+ &pci_apb_config_readl,
+ &pci_apb_config_readl,
+ &pci_apb_config_readl,
+};
+
+static void apb_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ //PCIBus *s = opaque;
+
+ switch (addr & 0x3f) {
+ case 0x00: // Control/Status
+ case 0x10: // AFSR
+ case 0x18: // AFAR
+ case 0x20: // Diagnostic
+ case 0x28: // Target address space
+ // XXX
+ default:
+ break;
+ }
+}
+
+static uint32_t apb_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ //PCIBus *s = opaque;
+ uint32_t val;
+
+ switch (addr & 0x3f) {
+ case 0x00: // Control/Status
+ case 0x10: // AFSR
+ case 0x18: // AFAR
+ case 0x20: // Diagnostic
+ case 0x28: // Target address space
+ // XXX
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static CPUWriteMemoryFunc *apb_config_write[] = {
+ &apb_config_writel,
+ &apb_config_writel,
+ &apb_config_writel,
+};
+
+static CPUReadMemoryFunc *apb_config_read[] = {
+ &apb_config_readl,
+ &apb_config_readl,
+ &apb_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_apb_write[] = {
+ &pci_host_data_writeb,
+ &pci_host_data_writew,
+ &pci_host_data_writel,
+};
+
+static CPUReadMemoryFunc *pci_apb_read[] = {
+ &pci_host_data_readb,
+ &pci_host_data_readw,
+ &pci_host_data_readl,
+};
+
+static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ cpu_outb(NULL, addr & 0xffff, val);
+}
+
+static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ cpu_outw(NULL, addr & 0xffff, val);
+}
+
+static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ cpu_outl(NULL, addr & 0xffff, val);
+}
+
+static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+
+ val = cpu_inb(NULL, addr & 0xffff);
+ return val;
+}
+
+static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+
+ val = cpu_inw(NULL, addr & 0xffff);
+ return val;
+}
+
+static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+
+ val = cpu_inl(NULL, addr & 0xffff);
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
+ &pci_apb_iowriteb,
+ &pci_apb_iowritew,
+ &pci_apb_iowritel,
+};
+
+static CPUReadMemoryFunc *pci_apb_ioread[] = {
+ &pci_apb_ioreadb,
+ &pci_apb_ioreadw,
+ &pci_apb_ioreadl,
+};
+
+/* ??? This is probably wrong. */
+static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
+ void *pic)
+{
+ APBState *s;
+ PCIDevice *d;
+ int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
+
+ s = qemu_mallocz(sizeof(APBState));
+ /* Ultrasparc APB main bus */
+ s->bus = pci_register_bus(pci_apb_set_irq, pic, 0);
+
+ pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
+ pci_apb_config_write, s);
+ apb_config = cpu_register_io_memory(0, apb_config_read,
+ apb_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
+ pci_apb_write, s);
+ pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
+ pci_apb_iowrite, s);
+
+ cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
+ cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
+ cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
+ cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
+
+ d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
+ -1, NULL, NULL);
+ d->config[0x00] = 0x8e; // vendor_id : Sun
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x00; // device_id
+ d->config[0x03] = 0xa0;
+ d->config[0x04] = 0x06; // command = bus master, pci mem
+ d->config[0x05] = 0x00;
+ d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+ d->config[0x07] = 0x03; // status = medium devsel
+ d->config[0x08] = 0x00; // revision
+ d->config[0x09] = 0x00; // programming i/f
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ return s->bus;
+}
+
+
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
- printf("cpu_set_apic_base: %016llx\n", val);
+ printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
#endif
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
- printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
+ printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
#endif
return s->apicbase;
}
--- /dev/null
+/*
+ * QEMU ATAPI CD-ROM Emulator
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved
+ here. */
+
+#include <vl.h>
+
+static void lba_to_msf(uint8_t *buf, int lba)
+{
+ lba += 150;
+ buf[0] = (lba / 75) / 60;
+ buf[1] = (lba / 75) % 60;
+ buf[2] = lba % 75;
+}
+
+/* same toc as bochs. Return -1 if error or the toc length */
+/* XXX: check this */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
+{
+ uint8_t *q;
+ int len;
+
+ if (start_track > 1 && start_track != 0xaa)
+ return -1;
+ q = buf + 2;
+ *q++ = 1; /* first session */
+ *q++ = 1; /* last session */
+ if (start_track <= 1) {
+ *q++ = 0; /* reserved */
+ *q++ = 0x14; /* ADR, control */
+ *q++ = 1; /* track number */
+ *q++ = 0; /* reserved */
+ if (msf) {
+ *q++ = 0; /* reserved */
+ lba_to_msf(q, 0);
+ q += 3;
+ } else {
+ /* sector 0 */
+ cpu_to_be32wu((uint32_t *)q, 0);
+ q += 4;
+ }
+ }
+ /* lead out track */
+ *q++ = 0; /* reserved */
+ *q++ = 0x16; /* ADR, control */
+ *q++ = 0xaa; /* track number */
+ *q++ = 0; /* reserved */
+ if (msf) {
+ *q++ = 0; /* reserved */
+ lba_to_msf(q, nb_sectors);
+ q += 3;
+ } else {
+ cpu_to_be32wu((uint32_t *)q, nb_sectors);
+ q += 4;
+ }
+ len = q - buf;
+ cpu_to_be16wu((uint16_t *)buf, len - 2);
+ return len;
+}
+
+/* mostly same info as PearPc */
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
+{
+ uint8_t *q;
+ int len;
+
+ q = buf + 2;
+ *q++ = 1; /* first session */
+ *q++ = 1; /* last session */
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* data track */
+ *q++ = 0; /* track number */
+ *q++ = 0xa0; /* lead-in */
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ *q++ = 0;
+ *q++ = 1; /* first track */
+ *q++ = 0x00; /* disk type */
+ *q++ = 0x00;
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* data track */
+ *q++ = 0; /* track number */
+ *q++ = 0xa1;
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ *q++ = 0;
+ *q++ = 1; /* last track */
+ *q++ = 0x00;
+ *q++ = 0x00;
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* data track */
+ *q++ = 0; /* track number */
+ *q++ = 0xa2; /* lead-out */
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ if (msf) {
+ *q++ = 0; /* reserved */
+ lba_to_msf(q, nb_sectors);
+ q += 3;
+ } else {
+ cpu_to_be32wu((uint32_t *)q, nb_sectors);
+ q += 4;
+ }
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* ADR, control */
+ *q++ = 0; /* track number */
+ *q++ = 1; /* point */
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ if (msf) {
+ *q++ = 0;
+ lba_to_msf(q, 0);
+ q += 3;
+ } else {
+ *q++ = 0;
+ *q++ = 0;
+ *q++ = 0;
+ *q++ = 0;
+ }
+
+ len = q - buf;
+ cpu_to_be16wu((uint16_t *)buf, len - 2);
+ return len;
+}
+
+
}
#if 0
#ifdef DEBUG_CUDA
- printf("latch=%d counter=%lld delta_next=%lld\n",
+ printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
s->latch, d, next_time - d);
#endif
#endif
as.freq = new_freq;
as.nchannels = 1 << (new_fmt & 1);
as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
+ as.endianness = 0;
if (i == ADC_CHANNEL) {
s->adc_voice =
"es1370.adc",
s,
es1370_adc_callback,
- &as,
- 0 /* little endian */
+ &as
);
}
else {
i ? "es1370.dac2" : "es1370.dac1",
s,
i ? es1370_dac2_callback : es1370_dac1_callback,
- &as,
- 0 /* litle endian */
+ &as
);
}
}
IO_WRITE_PROTO (es1370_writeb)
{
ES1370State *s = opaque;
- addr = es1370_fixup (s, addr);
uint32_t shift, mask;
+ addr = es1370_fixup (s, addr);
+
switch (addr) {
case ES1370_REG_CONTROL:
case ES1370_REG_CONTROL + 1:
#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f
-#define TI_BUFSZ 1024*1024 // XXX
+#define TI_BUFSZ 32
#define DMA_VER 0xa0000000
#define DMA_INTR 1
#define DMA_INTREN 0x10
+#define DMA_WRITE_MEM 0x100
#define DMA_LOADED 0x04000000
typedef struct ESPState ESPState;
-typedef int ESPDMAFunc(ESPState *s,
- target_phys_addr_t phys_addr,
- int transfer_size1);
-
struct ESPState {
BlockDriverState **bd;
uint8_t rregs[ESP_MAXREG];
uint32_t espdmaregs[ESPDMA_REGS];
uint32_t ti_size;
uint32_t ti_rptr, ti_wptr;
- int ti_dir;
uint8_t ti_buf[TI_BUFSZ];
+ int sense;
int dma;
- ESPDMAFunc *dma_cb;
- int64_t offset, len;
- int target;
+ SCSIDevice *scsi_dev[MAX_DISKS];
+ SCSIDevice *current_dev;
+ uint8_t cmdbuf[TI_BUFSZ];
+ int cmdlen;
+ int do_cmd;
};
#define STAT_DO 0x00
#define SEQ_0 0x0
#define SEQ_CD 0x4
-/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
-static void lba_to_msf(uint8_t *buf, int lba)
-{
- lba += 150;
- buf[0] = (lba / 75) / 60;
- buf[1] = (lba / 75) % 60;
- buf[2] = lba % 75;
-}
-
-static inline void cpu_to_ube16(uint8_t *buf, int val)
-{
- buf[0] = val >> 8;
- buf[1] = val;
-}
-
-static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
-{
- buf[0] = val >> 24;
- buf[1] = val >> 16;
- buf[2] = val >> 8;
- buf[3] = val;
-}
-
-/* same toc as bochs. Return -1 if error or the toc length */
-/* XXX: check this */
-static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
-{
- uint8_t *q;
- int len;
-
- if (start_track > 1 && start_track != 0xaa)
- return -1;
- q = buf + 2;
- *q++ = 1; /* first session */
- *q++ = 1; /* last session */
- if (start_track <= 1) {
- *q++ = 0; /* reserved */
- *q++ = 0x14; /* ADR, control */
- *q++ = 1; /* track number */
- *q++ = 0; /* reserved */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, 0);
- q += 3;
- } else {
- /* sector 0 */
- cpu_to_ube32(q, 0);
- q += 4;
- }
- }
- /* lead out track */
- *q++ = 0; /* reserved */
- *q++ = 0x16; /* ADR, control */
- *q++ = 0xaa; /* track number */
- *q++ = 0; /* reserved */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, nb_sectors);
- q += 3;
- } else {
- cpu_to_ube32(q, nb_sectors);
- q += 4;
- }
- len = q - buf;
- cpu_to_ube16(buf, len - 2);
- return len;
-}
-
-/* mostly same info as PearPc */
-static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf,
- int session_num)
-{
- uint8_t *q;
- int len;
-
- q = buf + 2;
- *q++ = 1; /* first session */
- *q++ = 1; /* last session */
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa0; /* lead-in */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- *q++ = 0;
- *q++ = 1; /* first track */
- *q++ = 0x00; /* disk type */
- *q++ = 0x00;
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa1;
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- *q++ = 0;
- *q++ = 1; /* last track */
- *q++ = 0x00;
- *q++ = 0x00;
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa2; /* lead-out */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, nb_sectors);
- q += 3;
- } else {
- cpu_to_ube32(q, nb_sectors);
- q += 4;
- }
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* ADR, control */
- *q++ = 0; /* track number */
- *q++ = 1; /* point */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- if (msf) {
- *q++ = 0;
- lba_to_msf(q, 0);
- q += 3;
- } else {
- *q++ = 0;
- *q++ = 0;
- *q++ = 0;
- *q++ = 0;
- }
-
- len = q - buf;
- cpu_to_ube16(buf, len - 2);
- return len;
-}
-
-static int esp_write_dma_cb(ESPState *s,
- target_phys_addr_t phys_addr,
- int transfer_size1)
+static int get_cmd(ESPState *s, uint8_t *buf)
{
- DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n",
- s->offset, s->len, s->ti_size, transfer_size1);
- bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len);
- s->offset = 0;
- s->len = 0;
- s->target = 0;
- return 0;
-}
-
-static void handle_satn(ESPState *s)
-{
- uint8_t buf[32];
uint32_t dmaptr, dmalen;
- unsigned int i;
- int64_t nb_sectors;
int target;
dmalen = s->wregs[0] | (s->wregs[1] << 8);
target = s->wregs[4] & 7;
- DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
+ DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
- DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
+ DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
+ s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
cpu_physical_memory_read(dmaptr, buf, dmalen);
} else {
buf[0] = 0;
memcpy(&buf[1], s->ti_buf, dmalen);
dmalen++;
}
- for (i = 0; i < dmalen; i++) {
- DPRINTF("Command %2.2x\n", buf[i]);
- }
- s->ti_dir = 0;
+
s->ti_size = 0;
s->ti_rptr = 0;
s->ti_wptr = 0;
- if (target >= 4 || !s->bd[target]) { // No such drive
+ if (target >= 4 || !s->scsi_dev[target]) {
+ // No such drive
s->rregs[4] = STAT_IN;
s->rregs[5] = INTR_DC;
s->rregs[6] = SEQ_0;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
- return;
+ return 0;
}
- switch (buf[1]) {
- case 0x0:
- DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
- break;
- case 0x12:
- DPRINTF("Inquiry (len %d)\n", buf[5]);
- memset(s->ti_buf, 0, 36);
- if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
- s->ti_buf[0] = 5;
- memcpy(&s->ti_buf[16], "QEMU CDROM ", 16);
- } else {
- s->ti_buf[0] = 0;
- memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16);
- }
- memcpy(&s->ti_buf[8], "QEMU ", 8);
- s->ti_buf[2] = 1;
- s->ti_buf[3] = 2;
- s->ti_buf[4] = 32;
- s->ti_dir = 1;
- s->ti_size = 36;
- break;
- case 0x1a:
- DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
- break;
- case 0x25:
- DPRINTF("Read Capacity (len %d)\n", buf[5]);
- memset(s->ti_buf, 0, 8);
- bdrv_get_geometry(s->bd[target], &nb_sectors);
- s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
- s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
- s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
- s->ti_buf[3] = nb_sectors & 0xff;
- s->ti_buf[4] = 0;
- s->ti_buf[5] = 0;
- if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
- s->ti_buf[6] = 8; // sector size 2048
- else
- s->ti_buf[6] = 2; // sector size 512
- s->ti_buf[7] = 0;
- s->ti_dir = 1;
- s->ti_size = 8;
- break;
- case 0x28:
- {
- int64_t offset, len;
-
- if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
- offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
- len = ((buf[8] << 8) | buf[9]) * 4;
- s->ti_size = len * 2048;
- } else {
- offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
- len = (buf[8] << 8) | buf[9];
- s->ti_size = len * 512;
- }
- DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
- if (s->ti_size > TI_BUFSZ) {
- DPRINTF("size too large %d\n", s->ti_size);
- }
- bdrv_read(s->bd[target], offset, s->ti_buf, len);
- // XXX error handling
- s->ti_dir = 1;
- break;
- }
- case 0x2a:
- {
- int64_t offset, len;
-
- if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
- offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
- len = ((buf[8] << 8) | buf[9]) * 4;
- s->ti_size = len * 2048;
- } else {
- offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
- len = (buf[8] << 8) | buf[9];
- s->ti_size = len * 512;
- }
- DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
- if (s->ti_size > TI_BUFSZ) {
- DPRINTF("size too large %d\n", s->ti_size);
- }
- s->dma_cb = esp_write_dma_cb;
- s->offset = offset;
- s->len = len;
- s->target = target;
- // XXX error handling
- s->ti_dir = 0;
- break;
- }
- case 0x43:
- {
- int start_track, format, msf, len;
-
- msf = buf[2] & 2;
- format = buf[3] & 0xf;
- start_track = buf[7];
- bdrv_get_geometry(s->bd[target], &nb_sectors);
- DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
- switch(format) {
- case 0:
- len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- s->ti_size = len;
- break;
- case 1:
- /* multi session : only a single session defined */
- memset(buf, 0, 12);
- buf[1] = 0x0a;
- buf[2] = 0x01;
- buf[3] = 0x01;
- s->ti_size = 12;
- break;
- case 2:
- len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- s->ti_size = len;
- break;
- default:
- error_cmd:
- DPRINTF("Read TOC error\n");
- // XXX error handling
- break;
- }
- s->ti_dir = 1;
- break;
+ s->current_dev = s->scsi_dev[target];
+ return dmalen;
+}
+
+static void do_cmd(ESPState *s, uint8_t *buf)
+{
+ int32_t datalen;
+ int lun;
+
+ DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
+ lun = buf[0] & 7;
+ datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
+ if (datalen == 0) {
+ s->ti_size = 0;
+ } else {
+ s->rregs[4] = STAT_IN | STAT_TC;
+ if (datalen > 0) {
+ s->rregs[4] |= STAT_DI;
+ s->ti_size = datalen;
+ } else {
+ s->rregs[4] |= STAT_DO;
+ s->ti_size = -datalen;
}
- default:
- DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
- break;
}
- s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
}
-static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
+static void handle_satn(ESPState *s)
{
- uint32_t dmaptr, dmalen;
+ uint8_t buf[32];
+ int len;
- dmalen = s->wregs[0] | (s->wregs[1] << 8);
- DPRINTF("Transfer status len %d\n", dmalen);
+ len = get_cmd(s, buf);
+ if (len)
+ do_cmd(s, buf);
+}
+
+static void handle_satn_stop(ESPState *s)
+{
+ s->cmdlen = get_cmd(s, s->cmdbuf);
+ if (s->cmdlen) {
+ DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
+ s->do_cmd = 1;
+ s->espdmaregs[1] += s->cmdlen;
+ s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
+ s->rregs[5] = INTR_BS | INTR_FC;
+ s->rregs[6] = SEQ_CD;
+ s->espdmaregs[0] |= DMA_INTR;
+ pic_set_irq(s->irq, 1);
+ }
+}
+
+static void write_response(ESPState *s)
+{
+ uint32_t dmaptr;
+
+ DPRINTF("Transfer status (sense=%d)\n", s->sense);
+ s->ti_buf[0] = s->sense;
+ s->ti_buf[1] = 0;
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
- DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
- cpu_physical_memory_write(dmaptr, buf, len);
+ DPRINTF("DMA Direction: %c\n",
+ s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
+ cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
} else {
- memcpy(s->ti_buf, buf, len);
- s->ti_size = dmalen;
+ s->ti_size = 2;
s->ti_rptr = 0;
s->ti_wptr = 0;
- s->rregs[7] = dmalen;
+ s->rregs[7] = 2;
}
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
}
-static const uint8_t okbuf[] = {0, 0};
+static void esp_command_complete(void *opaque, uint32_t tag, int sense)
+{
+ ESPState *s = (ESPState *)opaque;
+
+ DPRINTF("SCSI Command complete\n");
+ if (s->ti_size != 0)
+ DPRINTF("SCSI command completed unexpectedly\n");
+ s->ti_size = 0;
+ if (sense)
+ DPRINTF("Command failed\n");
+ s->sense = sense;
+ s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
+}
static void handle_ti(ESPState *s)
{
- uint32_t dmaptr, dmalen;
+ uint32_t dmaptr, dmalen, minlen, len, from, to;
unsigned int i;
+ int to_device;
+ uint8_t buf[TARGET_PAGE_SIZE];
dmalen = s->wregs[0] | (s->wregs[1] << 8);
- DPRINTF("Transfer Information len %d\n", dmalen);
+ if (dmalen==0) {
+ dmalen=0x10000;
+ }
+
+ if (s->do_cmd)
+ minlen = (dmalen < 32) ? dmalen : 32;
+ else
+ minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
+ DPRINTF("Transfer Information len %d\n", minlen);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
- DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
- for (i = 0; i < s->ti_size; i++) {
+ /* Check if the transfer writes to to reads from the device. */
+ to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
+ DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
+ to_device ? 'r': 'w', dmaptr, s->ti_size);
+ from = s->espdmaregs[1];
+ to = from + minlen;
+ for (i = 0; i < minlen; i += len, from += len) {
dmaptr = iommu_translate(s->espdmaregs[1] + i);
- if (s->ti_dir)
- cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
- else
- cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
- }
- if (s->dma_cb) {
- s->dma_cb(s, s->espdmaregs[1], dmalen);
- s->dma_cb = NULL;
+ if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
+ len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
+ } else {
+ len = to - from;
+ }
+ DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
+ s->ti_size -= len;
+ if (s->do_cmd) {
+ DPRINTF("command len %d + %d\n", s->cmdlen, len);
+ cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
+ s->ti_size = 0;
+ s->cmdlen = 0;
+ s->do_cmd = 0;
+ do_cmd(s, s->cmdbuf);
+ return;
+ } else {
+ if (to_device) {
+ cpu_physical_memory_read(dmaptr, buf, len);
+ scsi_write_data(s->current_dev, buf, len);
+ } else {
+ scsi_read_data(s->current_dev, buf, len);
+ cpu_physical_memory_write(dmaptr, buf, len);
+ }
+ }
}
- s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
- s->rregs[5] = INTR_BS;
+ if (s->ti_size) {
+ s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
+ }
+ s->rregs[5] = INTR_BS;
s->rregs[6] = 0;
+ s->rregs[7] = 0;
s->espdmaregs[0] |= DMA_INTR;
- } else {
- s->ti_size = dmalen;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- s->rregs[7] = dmalen;
- }
+ } else if (s->do_cmd) {
+ DPRINTF("command len %d\n", s->cmdlen);
+ s->ti_size = 0;
+ s->cmdlen = 0;
+ s->do_cmd = 0;
+ do_cmd(s, s->cmdbuf);
+ return;
+ }
pic_set_irq(s->irq, 1);
}
s->ti_size = 0;
s->ti_rptr = 0;
s->ti_wptr = 0;
- s->ti_dir = 0;
s->dma = 0;
- s->dma_cb = NULL;
+ s->do_cmd = 0;
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
// FIFO
if (s->ti_size > 0) {
s->ti_size--;
- s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
+ if ((s->rregs[4] & 6) == 0) {
+ /* Data in/out. */
+ scsi_read_data(s->current_dev, &s->rregs[2], 0);
+ } else {
+ s->rregs[2] = s->ti_buf[s->ti_rptr++];
+ }
pic_set_irq(s->irq, 1);
}
if (s->ti_size == 0) {
break;
case 2:
// FIFO
- s->ti_size++;
- s->ti_buf[s->ti_wptr++] = val & 0xff;
+ if (s->do_cmd) {
+ s->cmdbuf[s->cmdlen++] = val & 0xff;
+ } else if ((s->rregs[4] & 6) == 0) {
+ uint8_t buf;
+ buf = val & 0xff;
+ s->ti_size--;
+ scsi_write_data(s->current_dev, &buf, 0);
+ } else {
+ s->ti_size++;
+ s->ti_buf[s->ti_wptr++] = val & 0xff;
+ }
break;
case 3:
s->rregs[saddr] = val;
break;
case 0x11:
DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
- dma_write(s, okbuf, 2);
+ write_response(s);
break;
case 0x12:
DPRINTF("Message Accepted (%2.2x)\n", val);
- dma_write(s, okbuf, 2);
+ write_response(s);
s->rregs[5] = INTR_DC;
s->rregs[6] = 0;
break;
DPRINTF("Set ATN (%2.2x)\n", val);
break;
case 0x42:
+ DPRINTF("Set ATN (%2.2x)\n", val);
handle_satn(s);
break;
case 0x43:
DPRINTF("Set ATN & stop (%2.2x)\n", val);
- handle_satn(s);
+ handle_satn_stop(s);
break;
default:
DPRINTF("Unhandled ESP command (%2.2x)\n", val);
val |= DMA_VER;
break;
case 1:
- s->espdmaregs[0] = DMA_LOADED;
+ s->espdmaregs[0] |= DMA_LOADED;
break;
default:
break;
qemu_put_be32s(f, &s->ti_size);
qemu_put_be32s(f, &s->ti_rptr);
qemu_put_be32s(f, &s->ti_wptr);
- qemu_put_be32s(f, &s->ti_dir);
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
qemu_put_be32s(f, &s->dma);
}
qemu_get_be32s(f, &s->ti_size);
qemu_get_be32s(f, &s->ti_rptr);
qemu_get_be32s(f, &s->ti_wptr);
- qemu_get_be32s(f, &s->ti_dir);
qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
qemu_get_be32s(f, &s->dma);
{
ESPState *s;
int esp_io_memory, espdma_io_memory;
+ int i;
s = qemu_mallocz(sizeof(ESPState));
if (!s)
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
+ for (i = 0; i < MAX_DISKS; i++) {
+ if (bs_table[i]) {
+ s->scsi_dev[i] =
+ scsi_disk_init(bs_table[i], esp_command_complete, s);
+ }
+ }
}
--- /dev/null
+/*
+ * QEMU Grackle (heathrow PPC) PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState GrackleState;
+
+static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ GrackleState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ s->config_reg = val;
+}
+
+static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
+{
+ GrackleState *s = opaque;
+ uint32_t val;
+
+ val = s->config_reg;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
+ &pci_grackle_config_writel,
+ &pci_grackle_config_writel,
+ &pci_grackle_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_grackle_config_read[] = {
+ &pci_grackle_config_readl,
+ &pci_grackle_config_readl,
+ &pci_grackle_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_grackle_write[] = {
+ &pci_host_data_writeb,
+ &pci_host_data_writew,
+ &pci_host_data_writel,
+};
+
+static CPUReadMemoryFunc *pci_grackle_read[] = {
+ &pci_host_data_readb,
+ &pci_host_data_readw,
+ &pci_host_data_readl,
+};
+
+/* XXX: we do not simulate the hardware - we rely on the BIOS to
+ set correctly for irq line field */
+static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_grackle_init(uint32_t base, void *pic)
+{
+ GrackleState *s;
+ PCIDevice *d;
+ int pci_mem_config, pci_mem_data;
+
+ s = qemu_mallocz(sizeof(GrackleState));
+ s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0);
+
+ pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
+ pci_grackle_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
+ pci_grackle_write, s);
+ cpu_register_physical_memory(base, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
+ d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice),
+ 0, NULL, NULL);
+ d->config[0x00] = 0x57; // vendor_id
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x02; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x09] = 0x01;
+ d->config[0x0a] = 0x00; // class_sub = host
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x00; // header_type
+
+ d->config[0x18] = 0x00; // primary_bus
+ d->config[0x19] = 0x01; // secondary_bus
+ d->config[0x1a] = 0x00; // subordinate_bus
+ d->config[0x1c] = 0x00;
+ d->config[0x1d] = 0x00;
+
+ d->config[0x20] = 0x00; // memory_base
+ d->config[0x21] = 0x00;
+ d->config[0x22] = 0x01; // memory_limit
+ d->config[0x23] = 0x00;
+
+ d->config[0x24] = 0x00; // prefetchable_memory_base
+ d->config[0x25] = 0x00;
+ d->config[0x26] = 0x00; // prefetchable_memory_limit
+ d->config[0x27] = 0x00;
+
+#if 0
+ /* PCI2PCI bridge same values as PearPC - check this */
+ d->config[0x00] = 0x11; // vendor_id
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x26; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x02; // revision
+ d->config[0x0a] = 0x04; // class_sub = pci2pci
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x01; // header_type
+
+ d->config[0x18] = 0x0; // primary_bus
+ d->config[0x19] = 0x1; // secondary_bus
+ d->config[0x1a] = 0x1; // subordinate_bus
+ d->config[0x1c] = 0x10; // io_base
+ d->config[0x1d] = 0x20; // io_limit
+
+ d->config[0x20] = 0x80; // memory_base
+ d->config[0x21] = 0x80;
+ d->config[0x22] = 0x90; // memory_limit
+ d->config[0x23] = 0x80;
+
+ d->config[0x24] = 0x00; // prefetchable_memory_base
+ d->config[0x25] = 0x84;
+ d->config[0x26] = 0x00; // prefetchable_memory_limit
+ d->config[0x27] = 0x85;
+#endif
+ return s->bus;
+}
+
for (i = 0; i < 16; i++) {
count = irq_count[i];
if (count > 0)
- term_printf("%2d: %lld\n", i, count);
+ term_printf("%2d: %" PRId64 "\n", i, count);
}
#endif
}
}
}
-/* same toc as bochs. Return -1 if error or the toc length */
-/* XXX: check this */
-static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
-{
- uint8_t *q;
- int nb_sectors, len;
-
- if (start_track > 1 && start_track != 0xaa)
- return -1;
- q = buf + 2;
- *q++ = 1; /* first session */
- *q++ = 1; /* last session */
- if (start_track <= 1) {
- *q++ = 0; /* reserved */
- *q++ = 0x14; /* ADR, control */
- *q++ = 1; /* track number */
- *q++ = 0; /* reserved */
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, 0);
- q += 3;
- } else {
- /* sector 0 */
- cpu_to_ube32(q, 0);
- q += 4;
- }
- }
- /* lead out track */
- *q++ = 0; /* reserved */
- *q++ = 0x16; /* ADR, control */
- *q++ = 0xaa; /* track number */
- *q++ = 0; /* reserved */
- nb_sectors = s->nb_sectors >> 2;
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, nb_sectors);
- q += 3;
- } else {
- cpu_to_ube32(q, nb_sectors);
- q += 4;
- }
- len = q - buf;
- cpu_to_ube16(buf, len - 2);
- return len;
-}
-
-/* mostly same info as PearPc */
-static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf,
- int session_num)
-{
- uint8_t *q;
- int nb_sectors, len;
-
- q = buf + 2;
- *q++ = 1; /* first session */
- *q++ = 1; /* last session */
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa0; /* lead-in */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- *q++ = 0;
- *q++ = 1; /* first track */
- *q++ = 0x00; /* disk type */
- *q++ = 0x00;
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa1;
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- *q++ = 0;
- *q++ = 1; /* last track */
- *q++ = 0x00;
- *q++ = 0x00;
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* data track */
- *q++ = 0; /* track number */
- *q++ = 0xa2; /* lead-out */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- nb_sectors = s->nb_sectors >> 2;
- if (msf) {
- *q++ = 0; /* reserved */
- lba_to_msf(q, nb_sectors);
- q += 3;
- } else {
- cpu_to_ube32(q, nb_sectors);
- q += 4;
- }
-
- *q++ = 1; /* session number */
- *q++ = 0x14; /* ADR, control */
- *q++ = 0; /* track number */
- *q++ = 1; /* point */
- *q++ = 0; /* min */
- *q++ = 0; /* sec */
- *q++ = 0; /* frame */
- if (msf) {
- *q++ = 0;
- lba_to_msf(q, 0);
- q += 3;
- } else {
- *q++ = 0;
- *q++ = 0;
- *q++ = 0;
- *q++ = 0;
- }
-
- len = q - buf;
- cpu_to_ube16(buf, len - 2);
- return len;
-}
-
static void ide_atapi_cmd(IDEState *s)
{
const uint8_t *packet;
start_track = packet[6];
switch(format) {
case 0:
- len = cdrom_read_toc(s, buf, msf, start_track);
+ len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track);
if (len < 0)
goto error_cmd;
ide_atapi_cmd_reply(s, len, max_len);
ide_atapi_cmd_reply(s, 12, max_len);
break;
case 2:
- len = cdrom_read_toc_raw(s, buf, msf, start_track);
+ len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track);
if (len < 0)
goto error_cmd;
ide_atapi_cmd_reply(s, len, max_len);
break;
case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
+ if (s->bs)
+ bdrv_flush(s->bs);
+ s->status = READY_STAT;
+ ide_set_irq(s);
+ break;
case WIN_STANDBYNOW1:
case WIN_IDLEIMMEDIATE:
s->status = READY_STAT;
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
{
PCIIDEState *d;
uint8_t *pci_conf;
/* register a function 1 of PIIX3 */
d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE",
sizeof(PCIIDEState),
- ((PCIDevice *)piix3_state)->devfn + 1,
+ devfn,
NULL, NULL);
d->type = IDE_TYPE_PIIX3;
--- /dev/null
+/*
+ * QEMU LSI53C895A SCSI Host Bus Adapter emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+/* ??? Need to check if the {read,write}[wl] routines work properly on
+ big-endian targets. */
+
+#include "vl.h"
+
+//#define DEBUG_LSI
+//#define DEBUG_LSI_REG
+
+#ifdef DEBUG_LSI
+#define DPRINTF(fmt, args...) \
+do { printf("lsi_scsi: " fmt , ##args); } while (0)
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0)
+#endif
+
+#define LSI_SCNTL0_TRG 0x01
+#define LSI_SCNTL0_AAP 0x02
+#define LSI_SCNTL0_EPC 0x08
+#define LSI_SCNTL0_WATN 0x10
+#define LSI_SCNTL0_START 0x20
+
+#define LSI_SCNTL1_SST 0x01
+#define LSI_SCNTL1_IARB 0x02
+#define LSI_SCNTL1_AESP 0x04
+#define LSI_SCNTL1_RST 0x08
+#define LSI_SCNTL1_CON 0x10
+#define LSI_SCNTL1_DHP 0x20
+#define LSI_SCNTL1_ADB 0x40
+#define LSI_SCNTL1_EXC 0x80
+
+#define LSI_SCNTL2_WSR 0x01
+#define LSI_SCNTL2_VUE0 0x02
+#define LSI_SCNTL2_VUE1 0x04
+#define LSI_SCNTL2_WSS 0x08
+#define LSI_SCNTL2_SLPHBEN 0x10
+#define LSI_SCNTL2_SLPMD 0x20
+#define LSI_SCNTL2_CHM 0x40
+#define LSI_SCNTL2_SDU 0x80
+
+#define LSI_ISTAT0_DIP 0x01
+#define LSI_ISTAT0_SIP 0x02
+#define LSI_ISTAT0_INTF 0x04
+#define LSI_ISTAT0_CON 0x08
+#define LSI_ISTAT0_SEM 0x10
+#define LSI_ISTAT0_SIGP 0x20
+#define LSI_ISTAT0_SRST 0x40
+#define LSI_ISTAT0_ABRT 0x80
+
+#define LSI_ISTAT1_SI 0x01
+#define LSI_ISTAT1_SRUN 0x02
+#define LSI_ISTAT1_FLSH 0x04
+
+#define LSI_SSTAT0_SDP0 0x01
+#define LSI_SSTAT0_RST 0x02
+#define LSI_SSTAT0_WOA 0x04
+#define LSI_SSTAT0_LOA 0x08
+#define LSI_SSTAT0_AIP 0x10
+#define LSI_SSTAT0_OLF 0x20
+#define LSI_SSTAT0_ORF 0x40
+#define LSI_SSTAT0_ILF 0x80
+
+#define LSI_SIST0_PAR 0x01
+#define LSI_SIST0_RST 0x02
+#define LSI_SIST0_UDC 0x04
+#define LSI_SIST0_SGE 0x08
+#define LSI_SIST0_RSL 0x10
+#define LSI_SIST0_SEL 0x20
+#define LSI_SIST0_CMP 0x40
+#define LSI_SIST0_MA 0x80
+
+#define LSI_SIST1_HTH 0x01
+#define LSI_SIST1_GEN 0x02
+#define LSI_SIST1_STO 0x04
+#define LSI_SIST1_SBMC 0x10
+
+#define LSI_SOCL_IO 0x01
+#define LSI_SOCL_CD 0x02
+#define LSI_SOCL_MSG 0x04
+#define LSI_SOCL_ATN 0x08
+#define LSI_SOCL_SEL 0x10
+#define LSI_SOCL_BSY 0x20
+#define LSI_SOCL_ACK 0x40
+#define LSI_SOCL_REQ 0x80
+
+#define LSI_DSTAT_IID 0x01
+#define LSI_DSTAT_SIR 0x04
+#define LSI_DSTAT_SSI 0x08
+#define LSI_DSTAT_ABRT 0x10
+#define LSI_DSTAT_BF 0x20
+#define LSI_DSTAT_MDPE 0x40
+#define LSI_DSTAT_DFE 0x80
+
+#define LSI_DCNTL_COM 0x01
+#define LSI_DCNTL_IRQD 0x02
+#define LSI_DCNTL_STD 0x04
+#define LSI_DCNTL_IRQM 0x08
+#define LSI_DCNTL_SSM 0x10
+#define LSI_DCNTL_PFEN 0x20
+#define LSI_DCNTL_PFF 0x40
+#define LSI_DCNTL_CLSE 0x80
+
+#define LSI_DMODE_MAN 0x01
+#define LSI_DMODE_BOF 0x02
+#define LSI_DMODE_ERMP 0x04
+#define LSI_DMODE_ERL 0x08
+#define LSI_DMODE_DIOM 0x10
+#define LSI_DMODE_SIOM 0x20
+
+#define LSI_CTEST2_DACK 0x01
+#define LSI_CTEST2_DREQ 0x02
+#define LSI_CTEST2_TEOP 0x04
+#define LSI_CTEST2_PCICIE 0x08
+#define LSI_CTEST2_CM 0x10
+#define LSI_CTEST2_CIO 0x20
+#define LSI_CTEST2_SIGP 0x40
+#define LSI_CTEST2_DDIR 0x80
+
+#define LSI_CTEST5_BL2 0x04
+#define LSI_CTEST5_DDIR 0x08
+#define LSI_CTEST5_MASR 0x10
+#define LSI_CTEST5_DFSN 0x20
+#define LSI_CTEST5_BBCK 0x40
+#define LSI_CTEST5_ADCK 0x80
+
+#define LSI_CCNTL0_DILS 0x01
+#define LSI_CCNTL0_DISFC 0x10
+#define LSI_CCNTL0_ENNDJ 0x20
+#define LSI_CCNTL0_PMJCTL 0x40
+#define LSI_CCNTL0_ENPMJ 0x80
+
+#define PHASE_DO 0
+#define PHASE_DI 1
+#define PHASE_CMD 2
+#define PHASE_ST 3
+#define PHASE_MO 6
+#define PHASE_MI 7
+#define PHASE_MASK 7
+
+/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
+#define LSI_MAX_DEVS 7
+
+typedef struct {
+ PCIDevice pci_dev;
+ int mmio_io_addr;
+ int ram_io_addr;
+ uint32_t script_ram_base;
+ uint32_t data_len;
+
+ int carry; /* ??? Should this be an a visible register somewhere? */
+ int sense;
+ uint8_t msg;
+ /* Nonzero if a Wait Reselect instruction has been issued. */
+ int waiting;
+ SCSIDevice *scsi_dev[LSI_MAX_DEVS];
+ SCSIDevice *current_dev;
+ int current_lun;
+
+ uint32_t dsa;
+ uint32_t temp;
+ uint32_t dnad;
+ uint32_t dbc;
+ uint8_t istat0;
+ uint8_t istat1;
+ uint8_t dcmd;
+ uint8_t dstat;
+ uint8_t dien;
+ uint8_t sist0;
+ uint8_t sist1;
+ uint8_t sien0;
+ uint8_t sien1;
+ uint8_t mbox0;
+ uint8_t mbox1;
+ uint8_t dfifo;
+ uint8_t ctest3;
+ uint8_t ctest4;
+ uint8_t ctest5;
+ uint8_t ccntl0;
+ uint8_t ccntl1;
+ uint32_t dsp;
+ uint32_t dsps;
+ uint8_t dmode;
+ uint8_t dcntl;
+ uint8_t scntl0;
+ uint8_t scntl1;
+ uint8_t scntl2;
+ uint8_t scntl3;
+ uint8_t sstat0;
+ uint8_t sstat1;
+ uint8_t scid;
+ uint8_t sxfer;
+ uint8_t socl;
+ uint8_t sdid;
+ uint8_t sfbr;
+ uint8_t stest1;
+ uint8_t stest2;
+ uint8_t stest3;
+ uint8_t stime0;
+ uint8_t respid0;
+ uint8_t respid1;
+ uint32_t mmrs;
+ uint32_t mmws;
+ uint32_t sfs;
+ uint32_t drs;
+ uint32_t sbms;
+ uint32_t dmbs;
+ uint32_t dnad64;
+ uint32_t pmjad1;
+ uint32_t pmjad2;
+ uint32_t rbc;
+ uint32_t ua;
+ uint32_t ia;
+ uint32_t sbc;
+ uint32_t csbc;
+ uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */
+
+ /* Script ram is stored as 32-bit words in host byteorder. */
+ uint32_t script_ram[2048];
+} LSIState;
+
+static void lsi_soft_reset(LSIState *s)
+{
+ DPRINTF("Reset\n");
+ s->carry = 0;
+
+ s->waiting = 0;
+ s->dsa = 0;
+ s->dnad = 0;
+ s->dbc = 0;
+ s->temp = 0;
+ memset(s->scratch, 0, sizeof(s->scratch));
+ s->istat0 = 0;
+ s->istat1 = 0;
+ s->dcmd = 0;
+ s->dstat = 0;
+ s->dien = 0;
+ s->sist0 = 0;
+ s->sist1 = 0;
+ s->sien0 = 0;
+ s->sien1 = 0;
+ s->mbox0 = 0;
+ s->mbox1 = 0;
+ s->dfifo = 0;
+ s->ctest3 = 0;
+ s->ctest4 = 0;
+ s->ctest5 = 0;
+ s->ccntl0 = 0;
+ s->ccntl1 = 0;
+ s->dsp = 0;
+ s->dsps = 0;
+ s->dmode = 0;
+ s->dcntl = 0;
+ s->scntl0 = 0xc0;
+ s->scntl1 = 0;
+ s->scntl2 = 0;
+ s->scntl3 = 0;
+ s->sstat0 = 0;
+ s->sstat1 = 0;
+ s->scid = 7;
+ s->sxfer = 0;
+ s->socl = 0;
+ s->stest1 = 0;
+ s->stest2 = 0;
+ s->stest3 = 0;
+ s->stime0 = 0;
+ s->respid0 = 0x80;
+ s->respid1 = 0;
+ s->mmrs = 0;
+ s->mmws = 0;
+ s->sfs = 0;
+ s->drs = 0;
+ s->sbms = 0;
+ s->dmbs = 0;
+ s->dnad64 = 0;
+ s->pmjad1 = 0;
+ s->pmjad2 = 0;
+ s->rbc = 0;
+ s->ua = 0;
+ s->ia = 0;
+ s->sbc = 0;
+ s->csbc = 0;
+}
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset);
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
+
+static inline uint32_t read_dword(LSIState *s, uint32_t addr)
+{
+ uint32_t buf;
+
+ /* Optimize reading from SCRIPTS RAM. */
+ if ((addr & 0xffffe000) == s->script_ram_base) {
+ return s->script_ram[(addr & 0x1fff) >> 2];
+ }
+ cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
+ return cpu_to_le32(buf);
+}
+
+static void lsi_stop_script(LSIState *s)
+{
+ s->istat1 &= ~LSI_ISTAT1_SRUN;
+}
+
+static void lsi_update_irq(LSIState *s)
+{
+ int level;
+ static int last_level;
+
+ /* It's unclear whether the DIP/SIP bits should be cleared when the
+ Interrupt Status Registers are cleared or when istat0 is read.
+ We currently do the formwer, which seems to work. */
+ level = 0;
+ if (s->dstat) {
+ if (s->dstat & s->dien)
+ level = 1;
+ s->istat0 |= LSI_ISTAT0_DIP;
+ } else {
+ s->istat0 &= ~LSI_ISTAT0_DIP;
+ }
+
+ if (s->sist0 || s->sist1) {
+ if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
+ level = 1;
+ s->istat0 |= LSI_ISTAT0_SIP;
+ } else {
+ s->istat0 &= ~LSI_ISTAT0_SIP;
+ }
+ if (s->istat0 & LSI_ISTAT0_INTF)
+ level = 1;
+
+ if (level != last_level) {
+ DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
+ level, s->dstat, s->sist1, s->sist0);
+ last_level = level;
+ }
+ pci_set_irq(&s->pci_dev, 0, level);
+}
+
+/* Stop SCRIPTS execution and raise a SCSI interrupt. */
+static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
+{
+ uint32_t mask0;
+ uint32_t mask1;
+
+ DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
+ stat1, stat0, s->sist1, s->sist0);
+ s->sist0 |= stat0;
+ s->sist1 |= stat1;
+ /* Stop processor on fatal or unmasked interrupt. As a special hack
+ we don't stop processing when raising STO. Instead continue
+ execution and stop at the next insn that accesses the SCSI bus. */
+ mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
+ mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
+ mask1 &= ~LSI_SIST1_STO;
+ if (s->sist0 & mask0 || s->sist1 & mask1) {
+ lsi_stop_script(s);
+ }
+ lsi_update_irq(s);
+}
+
+/* Stop SCRIPTS execution and raise a DMA interrupt. */
+static void lsi_script_dma_interrupt(LSIState *s, int stat)
+{
+ DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
+ s->dstat |= stat;
+ lsi_update_irq(s);
+ lsi_stop_script(s);
+}
+
+static inline void lsi_set_phase(LSIState *s, int phase)
+{
+ s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
+}
+
+static void lsi_bad_phase(LSIState *s, int out, int new_phase)
+{
+ /* Trigger a phase mismatch. */
+ if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
+ if ((s->ccntl0 & LSI_CCNTL0_PMJCTL) || out) {
+ s->dsp = s->pmjad1;
+ } else {
+ s->dsp = s->pmjad2;
+ }
+ DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
+ } else {
+ DPRINTF("Phase mismatch interrupt\n");
+ lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+ lsi_stop_script(s);
+ }
+ lsi_set_phase(s, new_phase);
+}
+
+static void lsi_do_dma(LSIState *s, int out)
+{
+ uint8_t buf[TARGET_PAGE_SIZE];
+ uint32_t addr;
+ uint32_t count;
+ int n;
+
+ count = s->dbc;
+ addr = s->dnad;
+ DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in",
+ addr, count, s->data_len);
+ /* ??? Too long transfers are truncated. Don't know if this is the
+ correct behavior. */
+ if (count > s->data_len) {
+ /* If the DMA length is greater then the device data length then
+ a phase mismatch will occur. */
+ count = s->data_len;
+ s->dbc = count;
+ lsi_bad_phase(s, out, PHASE_ST);
+ }
+
+ s->csbc += count;
+
+ /* ??? Set SFBR to first data byte. */
+ while (count) {
+ n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;
+ if (out) {
+ cpu_physical_memory_read(addr, buf, n);
+ scsi_write_data(s->current_dev, buf, n);
+ } else {
+ scsi_read_data(s->current_dev, buf, n);
+ cpu_physical_memory_write(addr, buf, n);
+ }
+ addr += n;
+ count -= n;
+ }
+}
+
+
+static void lsi_do_command(LSIState *s)
+{
+ uint8_t buf[16];
+ int n;
+
+ DPRINTF("Send command len=%d\n", s->dbc);
+ if (s->dbc > 16)
+ s->dbc = 16;
+ cpu_physical_memory_read(s->dnad, buf, s->dbc);
+ s->sfbr = buf[0];
+ n = scsi_send_command(s->current_dev, 0, buf, s->current_lun);
+ if (n > 0) {
+ s->data_len = n;
+ lsi_set_phase(s, PHASE_DI);
+ } else if (n < 0) {
+ s->data_len = -n;
+ lsi_set_phase(s, PHASE_DO);
+ }
+}
+
+static void lsi_command_complete(void *opaque, uint32_t tag, int sense)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ DPRINTF("Command complete sense=%d\n", sense);
+ s->sense = sense;
+ lsi_set_phase(s, PHASE_ST);
+}
+
+static void lsi_do_status(LSIState *s)
+{
+ DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense);
+ if (s->dbc != 1)
+ BADF("Bad Status move\n");
+ s->dbc = 1;
+ s->msg = s->sense;
+ cpu_physical_memory_write(s->dnad, &s->msg, 1);
+ s->sfbr = s->msg;
+ lsi_set_phase(s, PHASE_MI);
+ s->msg = 0; /* COMMAND COMPLETE */
+}
+
+static void lsi_disconnect(LSIState *s)
+{
+ s->scntl1 &= ~LSI_SCNTL1_CON;
+ s->sstat1 &= ~PHASE_MASK;
+}
+
+static void lsi_do_msgin(LSIState *s)
+{
+ DPRINTF("Message in len=%d\n", s->dbc);
+ s->dbc = 1;
+ s->sfbr = s->msg;
+ cpu_physical_memory_write(s->dnad, &s->msg, 1);
+ if (s->msg == 0) {
+ lsi_disconnect(s);
+ } else {
+ /* ??? Check if ATN (not yet implemented) is asserted and maybe
+ switch to PHASE_MO. */
+ lsi_set_phase(s, PHASE_CMD);
+ }
+}
+
+static void lsi_do_msgout(LSIState *s)
+{
+ uint8_t msg;
+
+ DPRINTF("MSG out len=%d\n", s->dbc);
+ if (s->dbc != 1) {
+ /* Multibyte messages not implemented. */
+ s->msg = 7; /* MESSAGE REJECT */
+ //s->dbc = 1;
+ //lsi_bad_phase(s, 1, PHASE_MI);
+ lsi_set_phase(s, PHASE_MI);
+ return;
+ }
+ cpu_physical_memory_read(s->dnad, &msg, 1);
+ s->sfbr = msg;
+ s->dnad++;
+
+ switch (msg) {
+ case 0x00:
+ DPRINTF("Got Disconnect\n");
+ lsi_disconnect(s);
+ return;
+ case 0x08:
+ DPRINTF("Got No Operation\n");
+ lsi_set_phase(s, PHASE_CMD);
+ return;
+ }
+ if ((msg & 0x80) == 0) {
+ DPRINTF("Unimplemented message 0x%d\n", msg);
+ s->msg = 7; /* MESSAGE REJECT */
+ lsi_bad_phase(s, 1, PHASE_MI);
+ return;
+ }
+ s->current_lun = msg & 7;
+ DPRINTF("Select LUN %d\n", s->current_lun);
+ lsi_set_phase(s, PHASE_CMD);
+}
+
+/* Sign extend a 24-bit value. */
+static inline int32_t sxt24(int32_t n)
+{
+ return (n << 8) >> 8;
+}
+
+static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
+{
+ int n;
+ uint8_t buf[TARGET_PAGE_SIZE];
+
+ DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
+ while (count) {
+ n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;
+ cpu_physical_memory_read(src, buf, n);
+ cpu_physical_memory_write(dest, buf, n);
+ src += n;
+ dest += n;
+ count -= n;
+ }
+}
+
+static void lsi_execute_script(LSIState *s)
+{
+ uint32_t insn;
+ uint32_t addr;
+ int opcode;
+
+ s->istat1 |= LSI_ISTAT1_SRUN;
+again:
+ insn = read_dword(s, s->dsp);
+ addr = read_dword(s, s->dsp + 4);
+ DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
+ s->dsps = addr;
+ s->dcmd = insn >> 24;
+ s->dsp += 8;
+ switch (insn >> 30) {
+ case 0: /* Block move. */
+ if (s->sist1 & LSI_SIST1_STO) {
+ DPRINTF("Delayed select timeout\n");
+ lsi_stop_script(s);
+ break;
+ }
+ s->dbc = insn & 0xffffff;
+ s->rbc = s->dbc;
+ if (insn & (1 << 29)) {
+ /* Indirect addressing. */
+ addr = read_dword(s, addr);
+ } else if (insn & (1 << 28)) {
+ uint32_t buf[2];
+ int32_t offset;
+ /* Table indirect addressing. */
+ offset = sxt24(addr);
+ cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
+ s->dbc = cpu_to_le32(buf[0]);
+ addr = cpu_to_le32(buf[1]);
+ }
+ if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
+ DPRINTF("Wrong phase got %d expected %d\n",
+ s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
+ lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+ break;
+ }
+ s->dnad = addr;
+ switch (s->sstat1 & 0x7) {
+ case PHASE_DO:
+ lsi_do_dma(s, 1);
+ break;
+ case PHASE_DI:
+ lsi_do_dma(s, 0);
+ break;
+ case PHASE_CMD:
+ lsi_do_command(s);
+ break;
+ case PHASE_ST:
+ lsi_do_status(s);
+ break;
+ case PHASE_MO:
+ lsi_do_msgout(s);
+ break;
+ case PHASE_MI:
+ lsi_do_msgin(s);
+ break;
+ default:
+ BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
+ exit(1);
+ }
+ s->dfifo = s->dbc & 0xff;
+ s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
+ s->sbc = s->dbc;
+ s->rbc -= s->dbc;
+ s->ua = addr + s->dbc;
+ /* ??? Set ESA. */
+ s->ia = s->dsp - 8;
+ break;
+
+ case 1: /* IO or Read/Write instruction. */
+ opcode = (insn >> 27) & 7;
+ if (opcode < 5) {
+ uint32_t id;
+
+ if (insn & (1 << 25)) {
+ id = read_dword(s, s->dsa + sxt24(insn));
+ } else {
+ id = addr;
+ }
+ id = (id >> 16) & 0xf;
+ if (insn & (1 << 26)) {
+ addr = s->dsp + sxt24(addr);
+ }
+ s->dnad = addr;
+ switch (opcode) {
+ case 0: /* Select */
+ s->sstat0 |= LSI_SSTAT0_WOA;
+ s->scntl1 &= ~LSI_SCNTL1_IARB;
+ s->sdid = id;
+ if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) {
+ DPRINTF("Selected absent target %d\n", id);
+ lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
+ lsi_disconnect(s);
+ break;
+ }
+ DPRINTF("Selected target %d%s\n",
+ id, insn & (1 << 3) ? " ATN" : "");
+ /* ??? Linux drivers compain when this is set. Maybe
+ it only applies in low-level mode (unimplemented).
+ lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
+ s->current_dev = s->scsi_dev[id];
+ s->scntl1 |= LSI_SCNTL1_CON;
+ if (insn & (1 << 3)) {
+ s->socl |= LSI_SOCL_ATN;
+ }
+ lsi_set_phase(s, PHASE_MO);
+ break;
+ case 1: /* Disconnect */
+ DPRINTF("Wait Disconect\n");
+ s->scntl1 &= ~LSI_SCNTL1_CON;
+ break;
+ case 2: /* Wait Reselect */
+ DPRINTF("Wait Reselect\n");
+ s->waiting = 1;
+ break;
+ case 3: /* Set */
+ DPRINTF("Set%s%s%s%s\n",
+ insn & (1 << 3) ? " ATN" : "",
+ insn & (1 << 6) ? " ACK" : "",
+ insn & (1 << 9) ? " TM" : "",
+ insn & (1 << 10) ? " CC" : "");
+ if (insn & (1 << 3)) {
+ s->socl |= LSI_SOCL_ATN;
+ lsi_set_phase(s, PHASE_MO);
+ }
+ if (insn & (1 << 9)) {
+ BADF("Target mode not implemented\n");
+ exit(1);
+ }
+ if (insn & (1 << 10))
+ s->carry = 1;
+ break;
+ case 4: /* Clear */
+ DPRINTF("Clear%s%s%s%s\n",
+ insn & (1 << 3) ? " ATN" : "",
+ insn & (1 << 6) ? " ACK" : "",
+ insn & (1 << 9) ? " TM" : "",
+ insn & (1 << 10) ? " CC" : "");
+ if (insn & (1 << 3)) {
+ s->socl &= ~LSI_SOCL_ATN;
+ }
+ if (insn & (1 << 10))
+ s->carry = 0;
+ break;
+ }
+ } else {
+ uint8_t op0;
+ uint8_t op1;
+ uint8_t data8;
+ int reg;
+ int operator;
+#ifdef DEBUG_LSI
+ static const char *opcode_names[3] =
+ {"Write", "Read", "Read-Modify-Write"};
+ static const char *operator_names[8] =
+ {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
+#endif
+
+ reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
+ data8 = (insn >> 8) & 0xff;
+ opcode = (insn >> 27) & 7;
+ operator = (insn >> 24) & 7;
+ DPRINTF("%s reg 0x%x %s data8 %d%s\n",
+ opcode_names[opcode - 5], reg,
+ operator_names[operator], data8,
+ (insn & (1 << 23)) ? " SFBR" : "");
+ op0 = op1 = 0;
+ switch (opcode) {
+ case 5: /* From SFBR */
+ op0 = s->sfbr;
+ op1 = data8;
+ break;
+ case 6: /* To SFBR */
+ if (operator)
+ op0 = lsi_reg_readb(s, reg);
+ op1 = data8;
+ break;
+ case 7: /* Read-modify-write */
+ if (operator)
+ op0 = lsi_reg_readb(s, reg);
+ if (insn & (1 << 23)) {
+ op1 = s->sfbr;
+ } else {
+ op1 = data8;
+ }
+ break;
+ }
+
+ switch (operator) {
+ case 0: /* move */
+ op0 = op1;
+ break;
+ case 1: /* Shift left */
+ op1 = op0 >> 7;
+ op0 = (op0 << 1) | s->carry;
+ s->carry = op1;
+ break;
+ case 2: /* OR */
+ op0 |= op1;
+ break;
+ case 3: /* XOR */
+ op0 |= op1;
+ break;
+ case 4: /* AND */
+ op0 &= op1;
+ break;
+ case 5: /* SHR */
+ op1 = op0 & 1;
+ op0 = (op0 >> 1) | (s->carry << 7);
+ break;
+ case 6: /* ADD */
+ op0 += op1;
+ s->carry = op0 < op1;
+ break;
+ case 7: /* ADC */
+ op0 += op1 + s->carry;
+ if (s->carry)
+ s->carry = op0 <= op1;
+ else
+ s->carry = op0 < op1;
+ break;
+ }
+
+ switch (opcode) {
+ case 5: /* From SFBR */
+ case 7: /* Read-modify-write */
+ lsi_reg_writeb(s, reg, op0);
+ break;
+ case 6: /* To SFBR */
+ s->sfbr = op0;
+ break;
+ }
+ }
+ break;
+
+ case 2: /* Transfer Control. */
+ {
+ int cond;
+ int jmp;
+
+ if ((insn & 0x002e0000) == 0) {
+ DPRINTF("NOP\n");
+ break;
+ }
+ if (s->sist1 & LSI_SIST1_STO) {
+ DPRINTF("Delayed select timeout\n");
+ lsi_stop_script(s);
+ break;
+ }
+ cond = jmp = (insn & (1 << 19)) != 0;
+ if (cond == jmp && (insn & (1 << 21))) {
+ DPRINTF("Compare carry %d\n", s->carry == jmp);
+ cond = s->carry != 0;
+ }
+ if (cond == jmp && (insn & (1 << 17))) {
+ DPRINTF("Compare phase %d %c= %d\n",
+ (s->sstat1 & PHASE_MASK),
+ jmp ? '=' : '!',
+ ((insn >> 24) & 7));
+ cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
+ }
+ if (cond == jmp && (insn & (1 << 18))) {
+ uint8_t mask;
+
+ mask = (~insn >> 8) & 0xff;
+ DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
+ s->sfbr, mask, jmp ? '=' : '!', insn & mask);
+ cond = (s->sfbr & mask) == (insn & mask);
+ }
+ if (cond == jmp) {
+ if (insn & (1 << 23)) {
+ /* Relative address. */
+ addr = s->dsp + sxt24(addr);
+ }
+ switch ((insn >> 27) & 7) {
+ case 0: /* Jump */
+ DPRINTF("Jump to 0x%08x\n", addr);
+ s->dsp = addr;
+ break;
+ case 1: /* Call */
+ DPRINTF("Call 0x%08x\n", addr);
+ s->temp = s->dsp;
+ s->dsp = addr;
+ break;
+ case 2: /* Return */
+ DPRINTF("Return to 0x%08x\n", s->temp);
+ s->dsp = s->temp;
+ break;
+ case 3: /* Interrupt */
+ DPRINTF("Interrupt 0x%08x\n", s->dsps);
+ if ((insn & (1 << 20)) != 0) {
+ s->istat0 |= LSI_ISTAT0_INTF;
+ lsi_update_irq(s);
+ } else {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
+ }
+ break;
+ default:
+ DPRINTF("Illegal transfer control\n");
+ lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
+ break;
+ }
+ } else {
+ DPRINTF("Control condition failed\n");
+ }
+ }
+ break;
+
+ case 3:
+ if ((insn & (1 << 29)) == 0) {
+ /* Memory move. */
+ uint32_t dest;
+ /* ??? The docs imply the destination address is loaded into
+ the TEMP register. However the Linux drivers rely on
+ the value being presrved. */
+ dest = read_dword(s, s->dsp);
+ s->dsp += 4;
+ lsi_memcpy(s, dest, addr, insn & 0xffffff);
+ } else {
+ uint8_t data[7];
+ int reg;
+ int n;
+ int i;
+
+ if (insn & (1 << 28)) {
+ addr = s->dsa + sxt24(addr);
+ }
+ n = (insn & 7);
+ reg = (insn >> 16) & 0xff;
+ if (insn & (1 << 24)) {
+ DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
+ cpu_physical_memory_read(addr, data, n);
+ for (i = 0; i < n; i++) {
+ lsi_reg_writeb(s, reg + i, data[i]);
+ }
+ } else {
+ DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
+ for (i = 0; i < n; i++) {
+ data[i] = lsi_reg_readb(s, reg + i);
+ }
+ cpu_physical_memory_write(addr, data, n);
+ }
+ }
+ }
+ /* ??? Need to avoid infinite loops. */
+ if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
+ if (s->dcntl & LSI_DCNTL_SSM) {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
+ } else {
+ goto again;
+ }
+ }
+ DPRINTF("SCRIPTS execution stopped\n");
+}
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset)
+{
+ uint8_t tmp;
+#define CASE_GET_REG32(name, addr) \
+ case addr: return s->name & 0xff; \
+ case addr + 1: return (s->name >> 8) & 0xff; \
+ case addr + 2: return (s->name >> 16) & 0xff; \
+ case addr + 3: return (s->name >> 24) & 0xff;
+
+#ifdef DEBUG_LSI_REG
+ DPRINTF("Read reg %x\n", offset);
+#endif
+ switch (offset) {
+ case 0x00: /* SCNTL0 */
+ return s->scntl0;
+ case 0x01: /* SCNTL1 */
+ return s->scntl1;
+ case 0x02: /* SCNTL2 */
+ return s->scntl2;
+ case 0x03: /* SCNTL3 */
+ return s->scntl3;
+ case 0x04: /* SCID */
+ return s->scid;
+ case 0x05: /* SXFER */
+ return s->sxfer;
+ case 0x06: /* SDID */
+ return s->sdid;
+ case 0x07: /* GPREG0 */
+ return 0x7f;
+ case 0xb: /* SBCL */
+ /* ??? This is not correct. However it's (hopefully) only
+ used for diagnostics, so should be ok. */
+ return 0;
+ case 0xc: /* DSTAT */
+ tmp = s->dstat | 0x80;
+ if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
+ s->dstat = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x0d: /* SSTAT0 */
+ return s->sstat0;
+ case 0x0e: /* SSTAT1 */
+ return s->sstat1;
+ case 0x0f: /* SSTAT2 */
+ return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
+ CASE_GET_REG32(dsa, 0x10)
+ case 0x14: /* ISTAT0 */
+ return s->istat0;
+ case 0x16: /* MBOX0 */
+ return s->mbox0;
+ case 0x17: /* MBOX1 */
+ return s->mbox1;
+ case 0x18: /* CTEST0 */
+ return 0xff;
+ case 0x19: /* CTEST1 */
+ return 0;
+ case 0x1a: /* CTEST2 */
+ tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM;
+ if (s->istat0 & LSI_ISTAT0_SIGP) {
+ s->istat0 &= ~LSI_ISTAT0_SIGP;
+ tmp |= LSI_CTEST2_SIGP;
+ }
+ return tmp;
+ case 0x1b: /* CTEST3 */
+ return s->ctest3;
+ CASE_GET_REG32(temp, 0x1c)
+ case 0x20: /* DFIFO */
+ return 0;
+ case 0x21: /* CTEST4 */
+ return s->ctest4;
+ case 0x22: /* CTEST5 */
+ return s->ctest5;
+ case 0x24: /* DBC[0:7] */
+ return s->dbc & 0xff;
+ case 0x25: /* DBC[8:15] */
+ return (s->dbc >> 8) & 0xff;
+ case 0x26: /* DBC[16->23] */
+ return (s->dbc >> 16) & 0xff;
+ case 0x27: /* DCMD */
+ return s->dcmd;
+ CASE_GET_REG32(dsp, 0x2c)
+ CASE_GET_REG32(dsps, 0x30)
+ CASE_GET_REG32(scratch[0], 0x34)
+ case 0x38: /* DMODE */
+ return s->dmode;
+ case 0x39: /* DIEN */
+ return s->dien;
+ case 0x3b: /* DCNTL */
+ return s->dcntl;
+ case 0x40: /* SIEN0 */
+ return s->sien0;
+ case 0x41: /* SIEN1 */
+ return s->sien1;
+ case 0x42: /* SIST0 */
+ tmp = s->sist0;
+ s->sist0 = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x43: /* SIST1 */
+ tmp = s->sist1;
+ s->sist1 = 0;
+ lsi_update_irq(s);
+ return tmp;
+ case 0x47: /* GPCNTL0 */
+ return 0x0f;
+ case 0x48: /* STIME0 */
+ return s->stime0;
+ case 0x4a: /* RESPID0 */
+ return s->respid0;
+ case 0x4b: /* RESPID1 */
+ return s->respid1;
+ case 0x4d: /* STEST1 */
+ return s->stest1;
+ case 0x4e: /* STEST2 */
+ return s->stest2;
+ case 0x4f: /* STEST3 */
+ return s->stest3;
+ case 0x52: /* STEST4 */
+ return 0xe0;
+ case 0x56: /* CCNTL0 */
+ return s->ccntl0;
+ case 0x57: /* CCNTL1 */
+ return s->ccntl1;
+ case 0x58: case 0x59: /* SBDL */
+ return 0;
+ CASE_GET_REG32(mmrs, 0xa0)
+ CASE_GET_REG32(mmws, 0xa4)
+ CASE_GET_REG32(sfs, 0xa8)
+ CASE_GET_REG32(drs, 0xac)
+ CASE_GET_REG32(sbms, 0xb0)
+ CASE_GET_REG32(dmbs, 0xb4)
+ CASE_GET_REG32(dnad64, 0xb8)
+ CASE_GET_REG32(pmjad1, 0xc0)
+ CASE_GET_REG32(pmjad2, 0xc4)
+ CASE_GET_REG32(rbc, 0xc8)
+ CASE_GET_REG32(ua, 0xcc)
+ CASE_GET_REG32(ia, 0xd4)
+ CASE_GET_REG32(sbc, 0xd8)
+ CASE_GET_REG32(csbc, 0xdc)
+ }
+ if (offset >= 0x5c && offset < 0xa0) {
+ int n;
+ int shift;
+ n = (offset - 0x58) >> 2;
+ shift = (offset & 3) * 8;
+ return (s->scratch[n] >> shift) & 0xff;
+ }
+ BADF("readb 0x%x\n", offset);
+ exit(1);
+#undef CASE_GET_REG32
+}
+
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
+{
+#define CASE_SET_REG32(name, addr) \
+ case addr : s->name &= 0xffffff00; s->name |= val; break; \
+ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
+ case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
+ case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
+
+#ifdef DEBUG_LSI_REG
+ DPRINTF("Write reg %x = %02x\n", offset, val);
+#endif
+ switch (offset) {
+ case 0x00: /* SCNTL0 */
+ s->scntl0 = val;
+ if (val & LSI_SCNTL0_START) {
+ BADF("Start sequence not implemented\n");
+ }
+ break;
+ case 0x01: /* SCNTL1 */
+ s->scntl1 = val & ~LSI_SCNTL1_SST;
+ if (val & LSI_SCNTL1_IARB) {
+ BADF("Immediate Arbritration not implemented\n");
+ }
+ if (val & LSI_SCNTL1_RST) {
+ s->sstat0 |= LSI_SSTAT0_RST;
+ lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
+ } else {
+ s->sstat0 &= ~LSI_SSTAT0_RST;
+ }
+ break;
+ case 0x02: /* SCNTL2 */
+ val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
+ s->scntl3 = val;
+ break;
+ case 0x03: /* SCNTL3 */
+ s->scntl3 = val;
+ break;
+ case 0x04: /* SCID */
+ s->scid = val;
+ break;
+ case 0x05: /* SXFER */
+ s->sxfer = val;
+ break;
+ case 0x07: /* GPREG0 */
+ break;
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ /* Linux writes to these readonly registers on startup. */
+ return;
+ CASE_SET_REG32(dsa, 0x10)
+ case 0x14: /* ISTAT0 */
+ s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
+ if (val & LSI_ISTAT0_ABRT) {
+ lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
+ }
+ if (val & LSI_ISTAT0_INTF) {
+ s->istat0 &= ~LSI_ISTAT0_INTF;
+ lsi_update_irq(s);
+ }
+ if (s->waiting && val & LSI_ISTAT0_SIGP) {
+ DPRINTF("Woken by SIGP\n");
+ s->waiting = 0;
+ s->dsp = s->dnad;
+ lsi_execute_script(s);
+ }
+ if (val & LSI_ISTAT0_SRST) {
+ lsi_soft_reset(s);
+ }
+ case 0x16: /* MBOX0 */
+ s->mbox0 = val;
+ case 0x17: /* MBOX1 */
+ s->mbox1 = val;
+ case 0x1b: /* CTEST3 */
+ s->ctest3 = val & 0x0f;
+ break;
+ CASE_SET_REG32(temp, 0x1c)
+ case 0x21: /* CTEST4 */
+ if (val & 7) {
+ BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
+ }
+ s->ctest4 = val;
+ break;
+ case 0x22: /* CTEST5 */
+ if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
+ BADF("CTEST5 DMA increment not implemented\n");
+ }
+ s->ctest5 = val;
+ break;
+ case 0x2c: /* DSPS[0:7] */
+ s->dsp &= 0xffffff00;
+ s->dsp |= val;
+ break;
+ case 0x2d: /* DSPS[8:15] */
+ s->dsp &= 0xffff00ff;
+ s->dsp |= val << 8;
+ break;
+ case 0x2e: /* DSPS[16:23] */
+ s->dsp &= 0xff00ffff;
+ s->dsp |= val << 16;
+ break;
+ case 0x2f: /* DSPS[14:31] */
+ s->dsp &= 0x00ffffff;
+ s->dsp |= val << 24;
+ if ((s->dmode & LSI_DMODE_MAN) == 0
+ && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+ lsi_execute_script(s);
+ break;
+ CASE_SET_REG32(dsps, 0x30)
+ CASE_SET_REG32(scratch[0], 0x34)
+ case 0x38: /* DMODE */
+ if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
+ BADF("IO mappings not implemented\n");
+ }
+ s->dmode = val;
+ break;
+ case 0x39: /* DIEN */
+ s->dien = val;
+ lsi_update_irq(s);
+ break;
+ case 0x3b: /* DCNTL */
+ s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
+ if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+ lsi_execute_script(s);
+ break;
+ case 0x40: /* SIEN0 */
+ s->sien0 = val;
+ lsi_update_irq(s);
+ break;
+ case 0x41: /* SIEN1 */
+ s->sien1 = val;
+ lsi_update_irq(s);
+ break;
+ case 0x47: /* GPCNTL0 */
+ break;
+ case 0x48: /* STIME0 */
+ s->stime0 = val;
+ break;
+ case 0x49: /* STIME1 */
+ if (val & 0xf) {
+ DPRINTF("General purpose timer not implemented\n");
+ /* ??? Raising the interrupt immediately seems to be sufficient
+ to keep the FreeBSD driver happy. */
+ lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
+ }
+ break;
+ case 0x4a: /* RESPID0 */
+ s->respid0 = val;
+ break;
+ case 0x4b: /* RESPID1 */
+ s->respid1 = val;
+ break;
+ case 0x4d: /* STEST1 */
+ s->stest1 = val;
+ break;
+ case 0x4e: /* STEST2 */
+ if (val & 1) {
+ BADF("Low level mode not implemented\n");
+ }
+ s->stest2 = val;
+ break;
+ case 0x4f: /* STEST3 */
+ if (val & 0x41) {
+ BADF("SCSI FIFO test mode not implemented\n");
+ }
+ s->stest3 = val;
+ break;
+ case 0x56: /* CCNTL0 */
+ s->ccntl0 = val;
+ break;
+ case 0x57: /* CCNTL1 */
+ s->ccntl1 = val;
+ break;
+ CASE_SET_REG32(mmrs, 0xa0)
+ CASE_SET_REG32(mmws, 0xa4)
+ CASE_SET_REG32(sfs, 0xa8)
+ CASE_SET_REG32(drs, 0xac)
+ CASE_SET_REG32(sbms, 0xb0)
+ CASE_SET_REG32(dmbs, 0xb4)
+ CASE_SET_REG32(dnad64, 0xb8)
+ CASE_SET_REG32(pmjad1, 0xc0)
+ CASE_SET_REG32(pmjad2, 0xc4)
+ CASE_SET_REG32(rbc, 0xc8)
+ CASE_SET_REG32(ua, 0xcc)
+ CASE_SET_REG32(ia, 0xd4)
+ CASE_SET_REG32(sbc, 0xd8)
+ CASE_SET_REG32(csbc, 0xdc)
+ default:
+ if (offset >= 0x5c && offset < 0xa0) {
+ int n;
+ int shift;
+ n = (offset - 0x58) >> 2;
+ shift = (offset & 3) * 8;
+ s->scratch[n] &= ~(0xff << shift);
+ s->scratch[n] |= (val & 0xff) << shift;
+ } else {
+ BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
+ }
+ }
+#undef CASE_SET_REG32
+}
+
+static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ addr &= 0xff;
+ lsi_reg_writeb(s, addr, val & 0xff);
+ lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+}
+
+static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ addr &= 0xff;
+ lsi_reg_writeb(s, addr, val & 0xff);
+ lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+ lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
+ lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
+}
+
+static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ return lsi_reg_readb(s, addr & 0xff);
+}
+
+static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t val;
+
+ addr &= 0xff;
+ val = lsi_reg_readb(s, addr);
+ val |= lsi_reg_readb(s, addr + 1) << 8;
+ return val;
+}
+
+static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t val;
+ addr &= 0xff;
+ val = lsi_reg_readb(s, addr);
+ val |= lsi_reg_readb(s, addr + 1) << 8;
+ val |= lsi_reg_readb(s, addr + 2) << 16;
+ val |= lsi_reg_readb(s, addr + 3) << 24;
+ return val;
+}
+
+static CPUReadMemoryFunc *lsi_mmio_readfn[3] = {
+ lsi_mmio_readb,
+ lsi_mmio_readw,
+ lsi_mmio_readl,
+};
+
+static CPUWriteMemoryFunc *lsi_mmio_writefn[3] = {
+ lsi_mmio_writeb,
+ lsi_mmio_writew,
+ lsi_mmio_writel,
+};
+
+static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t newval;
+ int shift;
+
+ addr &= 0x1fff;
+ newval = s->script_ram[addr >> 2];
+ shift = (addr & 3) * 8;
+ newval &= ~(0xff << shift);
+ newval |= val << shift;
+ s->script_ram[addr >> 2] = newval;
+}
+
+static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t newval;
+
+ addr &= 0x1fff;
+ newval = s->script_ram[addr >> 2];
+ if (addr & 2) {
+ newval = (newval & 0xffff) | (val << 16);
+ } else {
+ newval = (newval & 0xffff0000) | val;
+ }
+ s->script_ram[addr >> 2] = newval;
+}
+
+
+static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ addr &= 0x1fff;
+ s->script_ram[addr >> 2] = val;
+}
+
+static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t val;
+
+ addr &= 0x1fff;
+ val = s->script_ram[addr >> 2];
+ val >>= (addr & 3) * 8;
+ return val & 0xff;
+}
+
+static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t val;
+
+ addr &= 0x1fff;
+ val = s->script_ram[addr >> 2];
+ if (addr & 2)
+ val >>= 16;
+ return le16_to_cpu(val);
+}
+
+static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ addr &= 0x1fff;
+ return le32_to_cpu(s->script_ram[addr >> 2]);
+}
+
+static CPUReadMemoryFunc *lsi_ram_readfn[3] = {
+ lsi_ram_readb,
+ lsi_ram_readw,
+ lsi_ram_readl,
+};
+
+static CPUWriteMemoryFunc *lsi_ram_writefn[3] = {
+ lsi_ram_writeb,
+ lsi_ram_writew,
+ lsi_ram_writel,
+};
+
+static uint32_t lsi_io_readb(void *opaque, uint32_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ return lsi_reg_readb(s, addr & 0xff);
+}
+
+static uint32_t lsi_io_readw(void *opaque, uint32_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t val;
+ addr &= 0xff;
+ val = lsi_reg_readb(s, addr);
+ val |= lsi_reg_readb(s, addr + 1) << 8;
+ return val;
+}
+
+static uint32_t lsi_io_readl(void *opaque, uint32_t addr)
+{
+ LSIState *s = (LSIState *)opaque;
+ uint32_t val;
+ addr &= 0xff;
+ val = lsi_reg_readb(s, addr);
+ val |= lsi_reg_readb(s, addr + 1) << 8;
+ val |= lsi_reg_readb(s, addr + 2) << 16;
+ val |= lsi_reg_readb(s, addr + 3) << 24;
+ return val;
+}
+
+static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+ lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+ addr &= 0xff;
+ lsi_reg_writeb(s, addr, val & 0xff);
+ lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+}
+
+static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ LSIState *s = (LSIState *)opaque;
+ addr &= 0xff;
+ lsi_reg_writeb(s, addr, val & 0xff);
+ lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
+ lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
+ lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff);
+}
+
+static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ LSIState *s = (LSIState *)pci_dev;
+
+ DPRINTF("Mapping IO at %08x\n", addr);
+
+ register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
+ register_ioport_read(addr, 256, 1, lsi_io_readb, s);
+ register_ioport_write(addr, 256, 2, lsi_io_writew, s);
+ register_ioport_read(addr, 256, 2, lsi_io_readw, s);
+ register_ioport_write(addr, 256, 4, lsi_io_writel, s);
+ register_ioport_read(addr, 256, 4, lsi_io_readl, s);
+}
+
+static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ LSIState *s = (LSIState *)pci_dev;
+
+ DPRINTF("Mapping ram at %08x\n", addr);
+ s->script_ram_base = addr;
+ cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
+}
+
+static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ LSIState *s = (LSIState *)pci_dev;
+
+ DPRINTF("Mapping registers at %08x\n", addr);
+ cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
+}
+
+void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id)
+{
+ LSIState *s = (LSIState *)opaque;
+
+ if (id < 0) {
+ for (id = 0; id < LSI_MAX_DEVS; id++) {
+ if (s->scsi_dev[id] == NULL)
+ break;
+ }
+ }
+ if (id >= LSI_MAX_DEVS) {
+ BADF("Bad Device ID %d\n", id);
+ return;
+ }
+ if (s->scsi_dev[id]) {
+ DPRINTF("Destroying device %d\n", id);
+ scsi_disk_destroy(s->scsi_dev[id]);
+ }
+ DPRINTF("Attaching block device %d\n", id);
+ s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s);
+}
+
+void *lsi_scsi_init(PCIBus *bus, int devfn)
+{
+ LSIState *s;
+
+ s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA",
+ sizeof(*s), devfn, NULL, NULL);
+ if (s == NULL) {
+ fprintf(stderr, "lsi-scsi: Failed to register PCI device\n");
+ return NULL;
+ }
+
+ s->pci_dev.config[0x00] = 0x00;
+ s->pci_dev.config[0x01] = 0x10;
+ s->pci_dev.config[0x02] = 0x12;
+ s->pci_dev.config[0x03] = 0x00;
+ s->pci_dev.config[0x0b] = 0x01;
+ s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
+
+ s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn,
+ lsi_mmio_writefn, s);
+ s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn,
+ lsi_ram_writefn, s);
+
+ pci_register_io_region((struct PCIDevice *)s, 0, 256,
+ PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc);
+ pci_register_io_region((struct PCIDevice *)s, 1, 0x400,
+ PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc);
+ pci_register_io_region((struct PCIDevice *)s, 2, 0x2000,
+ PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc);
+
+ lsi_soft_reset(s);
+
+ return s;
+}
+
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
- tm.tm_year = fromBCD(val);
+ if (NVRAM->type == 8)
+ tm.tm_year = fromBCD(val) + 68; // Base year is 1968
+ else
+ tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
- retval = toBCD(tm.tm_year);
+ if (NVRAM->type == 8)
+ retval = toBCD(tm.tm_year - 68); // Base year is 1968
+ else
+ retval = toBCD(tm.tm_year);
break;
default:
/* Check lock registers state */
next++;
#if 0
if (logfile) {
- fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
+ fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
__func__, now, count, compare, next - now);
}
#endif
run. */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
- printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret == BIOS_SIZE) {
cpu_register_physical_memory((uint32_t)(0x1fc00000),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
- env->PC = 0xBFC00000;
- if (!kernel_filename)
- return;
} else {
/* not fatal */
fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
index = s->curpag << 8;
boundary = s->boundary << 8;
- if (index < boundary)
+ if (index <= boundary)
avail = boundary - index;
else
avail = (s->stop - s->start) - (index - boundary);
#ifndef CONFIG_DM
static IOAPICState *ioapic;
#endif /* !CONFIG_DM */
-static USBPort *usb_root_ports[2];
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
{
}
/* TSC handling */
-
uint64_t cpu_get_tsc(CPUX86State *env)
{
- return qemu_get_clock(vm_clock);
+ /* Note: when using kqemu, it is more logical to return the host TSC
+ because kqemu does not trap the RDTSC instruction for
+ performance reasons */
+#if USE_KQEMU
+ if (env->kqemu_enabled) {
+ return cpu_get_real_ticks();
+ } else
+#endif
+ {
+ return cpu_get_ticks();
+ }
}
#ifndef CONFIG_DM
case 'a':
case 'b':
rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
+ if (!fd_bootchk)
+ rtc_set_memory(s, 0x38, 0x01); /* disable signature check */
break;
default:
case 'c':
}
}
rtc_set_memory(s, 0x39, val);
-
- /* Disable check of 0x55AA signature on the last two bytes of
- first sector of disk. XXX: make it the default ? */
- // rtc_set_memory(s, 0x38, 1);
}
void ioport_set_a20(int enable)
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
/* PIIX4 acpi pci configuration space, func 3 */
-extern void pci_piix4_acpi_init(PCIBus *bus);
+extern void pci_piix4_acpi_init(PCIBus *bus, int devfn);
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
int bios_size, isa_bios_size;
#endif /* !NOBIOS */
PCIBus *pci_bus;
+ int piix3_devfn = -1;
CPUState *env;
NICInfo *nd;
if (pci_enabled) {
pci_bus = i440fx_init();
- piix3_init(pci_bus);
+ piix3_devfn = piix3_init(pci_bus);
} else {
pci_bus = NULL;
}
}
if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, bs_table);
+ pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
} else {
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
/* using PIIX4 acpi model */
if (pci_enabled && acpi_enabled)
- pci_piix4_acpi_init(pci_bus);
+ pci_piix4_acpi_init(pci_bus, piix3_devfn + 3);
if (pci_enabled && usb_enabled) {
- usb_uhci_init(pci_bus, usb_root_ports);
- usb_attach(usb_root_ports[0], vm_usb_hub);
+ usb_uhci_init(pci_bus, piix3_devfn + 2);
}
+ if (pci_enabled && acpi_enabled && 0) {
+ piix4_pm_init(pci_bus, piix3_devfn + 3);
+ }
+
+#if 0
+ /* ??? Need to figure out some way for the user to
+ specify SCSI devices. */
+ if (pci_enabled) {
+ void *scsi;
+ BlockDriverState *bdrv;
+
+ scsi = lsi_scsi_init(pci_bus, -1);
+ bdrv = bdrv_new("scsidisk");
+ bdrv_open(bdrv, "scsi_disk.img", 0);
+ lsi_scsi_attach(scsi, bdrv, -1);
+ bdrv = bdrv_new("scsicd");
+ bdrv_open(bdrv, "scsi_cd.iso", 0);
+ bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
+ lsi_scsi_attach(scsi, bdrv, -1);
+ }
+#endif
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
if (pci_enabled) {
pci_bios_init();
+ if (acpi_enabled)
+ acpi_bios_init();
}
}
//#define DEBUG_PCI
-#define PCI_VENDOR_ID 0x00 /* 16 bits */
-#define PCI_DEVICE_ID 0x02 /* 16 bits */
-#define PCI_COMMAND 0x04 /* 16 bits */
-#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
-#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
-#define PCI_CLASS_DEVICE 0x0a /* Device class */
-#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
-#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
-#define PCI_MIN_GNT 0x3e /* 8 bits */
-#define PCI_MAX_LAT 0x3f /* 8 bits */
-
-/* just used for simpler irq handling. */
-#define PCI_DEVICES_MAX 64
-#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
-
struct PCIBus {
int bus_num;
int devfn_min;
- void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level);
+ pci_set_irq_fn set_irq;
uint32_t config_reg; /* XXX: suppress */
/* low level pic */
SetIRQFunc *low_set_irq;
target_phys_addr_t pci_mem_base;
static int pci_irq_index;
-static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
static PCIBus *first_bus;
-static PCIBus *pci_register_bus(void)
+PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min)
{
PCIBus *bus;
bus = qemu_mallocz(sizeof(PCIBus));
+ bus->set_irq = set_irq;
+ bus->irq_opaque = pic;
+ bus->devfn_min = devfn_min;
first_bus = bus;
return bus;
}
+int pci_bus_num(PCIBus *s)
+{
+ return s->bus_num;
+}
+
void generic_pci_save(QEMUFile* f, void *opaque)
{
PCIDevice* s=(PCIDevice*)opaque;
*(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type);
}
-static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- s->config_reg = val;
-}
-
-static uint32_t pci_addr_readl(void* opaque, uint32_t addr)
+target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
{
- PCIBus *s = opaque;
- return s->config_reg;
+ return addr + pci_mem_base;
}
static void pci_update_mappings(PCIDevice *d)
isa_unassign_ioport(r->addr, r->size);
}
} else {
- cpu_register_physical_memory(r->addr + pci_mem_base,
+ cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
r->size,
IO_MEM_UNASSIGNED);
}
}
}
-static void pci_data_write(void *opaque, uint32_t addr,
- uint32_t val, int len)
+void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
{
PCIBus *s = opaque;
PCIDevice *pci_dev;
#if defined(DEBUG_PCI) && 0
printf("pci_data_write: addr=%08x val=%08x len=%d\n",
- s->config_reg, val, len);
+ addr, val, len);
#endif
- if (!(s->config_reg & (1 << 31))) {
- return;
- }
- bus_num = (s->config_reg >> 16) & 0xff;
+ bus_num = (addr >> 16) & 0xff;
if (bus_num != 0)
return;
- pci_dev = s->devices[(s->config_reg >> 8) & 0xff];
+ pci_dev = s->devices[(addr >> 8) & 0xff];
if (!pci_dev)
return;
- config_addr = (s->config_reg & 0xfc) | (addr & 3);
+ config_addr = addr & 0xff;
#if defined(DEBUG_PCI)
printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
pci_dev->name, config_addr, val, len);
pci_dev->config_write(pci_dev, config_addr, val, len);
}
-static uint32_t pci_data_read(void *opaque, uint32_t addr,
- int len)
+uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
{
PCIBus *s = opaque;
PCIDevice *pci_dev;
int config_addr, bus_num;
uint32_t val;
- if (!(s->config_reg & (1 << 31)))
- goto fail;
- bus_num = (s->config_reg >> 16) & 0xff;
+ bus_num = (addr >> 16) & 0xff;
if (bus_num != 0)
goto fail;
- pci_dev = s->devices[(s->config_reg >> 8) & 0xff];
+ pci_dev = s->devices[(addr >> 8) & 0xff];
if (!pci_dev) {
fail:
switch(len) {
}
goto the_end;
}
- config_addr = (s->config_reg & 0xfc) | (addr & 3);
+ config_addr = addr & 0xff;
val = pci_dev->config_read(pci_dev, config_addr, len);
#if defined(DEBUG_PCI)
printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
the_end:
#if defined(DEBUG_PCI) && 0
printf("pci_data_read: addr=%08x val=%08x len=%d\n",
- s->config_reg, val, len);
+ addr, val, len);
#endif
return val;
}
-static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val)
-{
- pci_data_write(opaque, addr, val, 1);
-}
-
-static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val)
-{
- pci_data_write(opaque, addr, val, 2);
-}
-
-static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val)
-{
- pci_data_write(opaque, addr, val, 4);
-}
-
-static uint32_t pci_data_readb(void* opaque, uint32_t addr)
-{
- return pci_data_read(opaque, addr, 1);
-}
-
-static uint32_t pci_data_readw(void* opaque, uint32_t addr)
-{
- return pci_data_read(opaque, addr, 2);
-}
-
-static uint32_t pci_data_readl(void* opaque, uint32_t addr)
-{
- return pci_data_read(opaque, addr, 4);
-}
-
-/* i440FX PCI bridge */
-
-static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level);
+/***********************************************************/
+/* generic PCI irq support */
-PCIBus *i440fx_init(void)
+/* 0 <= irq_num <= 3. level must be 0 or 1 */
+void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
{
- PCIBus *s;
- PCIDevice *d;
-
- s = pci_register_bus();
- s->set_irq = piix3_set_irq;
-
- register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
- register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
-
- register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
- register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
- register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
- register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
- register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
- register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
-
- d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0,
- NULL, NULL);
-
- d->config[0x00] = 0x86; // vendor_id
- d->config[0x01] = 0x80;
- d->config[0x02] = 0x37; // device_id
- d->config[0x03] = 0x12;
- d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x00; // class_sub = host2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x00; // header_type
- return s;
+ PCIBus *bus = pci_dev->bus;
+ bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level);
}
-/* PIIX3 PCI to ISA bridge */
-
-typedef struct PIIX3State {
- PCIDevice dev;
-} PIIX3State;
+/***********************************************************/
+/* monitor info on PCI */
-PIIX3State *piix3_state;
+typedef struct {
+ uint16_t class;
+ const char *desc;
+} pci_class_desc;
+
+static pci_class_desc pci_class_descriptions[] =
+{
+ { 0x0101, "IDE controller"},
+ { 0x0200, "Ethernet controller"},
+ { 0x0300, "VGA controller"},
+ { 0x0600, "Host bridge"},
+ { 0x0601, "ISA bridge"},
+ { 0x0604, "PCI bridge"},
+ { 0x0c03, "USB controller"},
+ { 0, NULL}
+};
-/* return the global irq number corresponding to a given device irq
- pin. We could also use the bus number to have a more precise
- mapping. */
-static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+static void pci_info_device(PCIDevice *d)
{
- int slot_addend;
- slot_addend = (pci_dev->devfn >> 3) - 1;
- return (irq_num + slot_addend) & 3;
-}
+ int i, class;
+ PCIIORegion *r;
+ pci_class_desc *desc;
-static inline int get_pci_irq_level(int irq_num)
-{
- int pic_level;
-#if (PCI_IRQ_WORDS == 2)
- pic_level = ((pci_irq_levels[irq_num][0] |
- pci_irq_levels[irq_num][1]) != 0);
-#else
- {
- int i;
- pic_level = 0;
- for(i = 0; i < PCI_IRQ_WORDS; i++) {
- if (pci_irq_levels[irq_num][i]) {
- pic_level = 1;
- break;
- }
- }
+ term_printf(" Bus %2d, device %3d, function %d:\n",
+ d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
+ class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE)));
+ term_printf(" ");
+ desc = pci_class_descriptions;
+ while (desc->desc && class != desc->class)
+ desc++;
+ if (desc->desc) {
+ term_printf("%s", desc->desc);
+ } else {
+ term_printf("Class %04x", class);
}
-#endif
- return pic_level;
-}
-
-static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
-{
- int irq_index, shift, pic_irq, pic_level;
- uint32_t *p;
-
- irq_num = pci_slot_get_pirq(pci_dev, irq_num);
- irq_index = pci_dev->irq_index;
- p = &pci_irq_levels[irq_num][irq_index >> 5];
- shift = (irq_index & 0x1f);
- *p = (*p & ~(1 << shift)) | (level << shift);
+ term_printf(": PCI device %04x:%04x\n",
+ le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))),
+ le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID))));
- /* now we change the pic irq level according to the piix irq mappings */
- /* XXX: optimize */
- pic_irq = piix3_state->dev.config[0x60 + irq_num];
- if (pic_irq < 16) {
- /* the pic level is the logical OR of all the PCI irqs mapped
- to it */
- pic_level = 0;
- if (pic_irq == piix3_state->dev.config[0x60])
- pic_level |= get_pci_irq_level(0);
- if (pic_irq == piix3_state->dev.config[0x61])
- pic_level |= get_pci_irq_level(1);
- if (pic_irq == piix3_state->dev.config[0x62])
- pic_level |= get_pci_irq_level(2);
- if (pic_irq == piix3_state->dev.config[0x63])
- pic_level |= get_pci_irq_level(3);
- pic_set_irq(pic_irq, pic_level);
+ if (d->config[PCI_INTERRUPT_PIN] != 0) {
+ term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
}
-}
-
-static void piix3_reset(PIIX3State *d)
-{
- uint8_t *pci_conf = d->dev.config;
-
- pci_conf[0x04] = 0x07; // master, memory and I/O
- pci_conf[0x05] = 0x00;
- pci_conf[0x06] = 0x00;
- pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
- pci_conf[0x4c] = 0x4d;
- pci_conf[0x4e] = 0x03;
- pci_conf[0x4f] = 0x00;
- pci_conf[0x60] = 0x80;
- pci_conf[0x69] = 0x02;
- pci_conf[0x70] = 0x80;
- pci_conf[0x76] = 0x0c;
- pci_conf[0x77] = 0x0c;
- pci_conf[0x78] = 0x02;
- pci_conf[0x79] = 0x00;
- pci_conf[0x80] = 0x00;
- pci_conf[0x82] = 0x00;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa2] = 0x00;
- pci_conf[0xa3] = 0x00;
- pci_conf[0xa4] = 0x00;
- pci_conf[0xa5] = 0x00;
- pci_conf[0xa6] = 0x00;
- pci_conf[0xa7] = 0x00;
- pci_conf[0xa8] = 0x0f;
- pci_conf[0xaa] = 0x00;
- pci_conf[0xab] = 0x00;
- pci_conf[0xac] = 0x00;
- pci_conf[0xae] = 0x00;
-}
-
-void piix3_init(PCIBus *bus)
-{
- PIIX3State *d;
- uint8_t *pci_conf;
-
- d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State),
- -1, NULL, NULL);
- register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
-
- piix3_state = d;
- pci_conf = d->dev.config;
-
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- pci_conf[0x03] = 0x70;
- pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
- pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
- pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
-
- piix3_reset(d);
-}
-
-/* PREP pci init */
-
-static inline void set_config(PCIBus *s, target_phys_addr_t addr)
-{
- int devfn, i;
-
- for(i = 0; i < 11; i++) {
- if ((addr & (1 << (11 + i))) != 0)
- break;
+ for(i = 0;i < PCI_NUM_REGIONS; i++) {
+ r = &d->io_regions[i];
+ if (r->size != 0) {
+ term_printf(" BAR%d: ", i);
+ if (r->type & PCI_ADDRESS_SPACE_IO) {
+ term_printf("I/O at 0x%04x [0x%04x].\n",
+ r->addr, r->addr + r->size - 1);
+ } else {
+ term_printf("32 bit memory at 0x%08x [0x%08x].\n",
+ r->addr, r->addr + r->size - 1);
+ }
+ }
}
- devfn = ((addr >> 8) & 7) | (i << 3);
- s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8);
-}
-
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- set_config(s, addr);
- pci_data_write(s, addr, val, 1);
-}
-
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- set_config(s, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr, val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- set_config(s, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr, val, 4);
-}
-
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- set_config(s, addr);
- val = pci_data_read(s, addr, 1);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- set_config(s, addr);
- val = pci_data_read(s, addr, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- set_config(s, addr);
- val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *PPC_PCIIO_write[] = {
- &PPC_PCIIO_writeb,
- &PPC_PCIIO_writew,
- &PPC_PCIIO_writel,
-};
-
-static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
- &PPC_PCIIO_readb,
- &PPC_PCIIO_readw,
- &PPC_PCIIO_readl,
-};
-
-static void prep_set_irq(PCIDevice *d, int irq_num, int level)
-{
- /* XXX: we do not simulate the hardware - we rely on the BIOS to
- set correctly for irq line field */
- pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_prep_init(void)
-{
- PCIBus *s;
- PCIDevice *d;
- int PPC_io_memory;
-
- s = pci_register_bus();
- s->set_irq = prep_set_irq;
-
- register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
- register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
-
- register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
- register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
- register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
- register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
- register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
- register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
-
- PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
- PPC_PCIIO_write, s);
- cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
-
- /* PCI host bridge */
- d = pci_register_device(s, "PREP Host Bridge - Motorola Raven",
- sizeof(PCIDevice), 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id : Motorola
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x01; // device_id : Raven
- d->config[0x03] = 0x48;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-
- return s;
-}
-
-
-/* Grackle PCI host */
-static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- s->config_reg = val;
-}
-
-static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = s->config_reg;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
- &pci_grackle_config_writel,
- &pci_grackle_config_writel,
- &pci_grackle_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_config_read[] = {
- &pci_grackle_config_readl,
- &pci_grackle_config_readl,
- &pci_grackle_config_readl,
-};
-
-static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- pci_data_write(s, addr, val, 1);
-}
-
-static void pci_grackle_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr, val, 2);
-}
-
-static void pci_grackle_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr, val, 4);
-}
-
-static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- val = pci_data_read(s, addr, 1);
- return val;
-}
-
-static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- val = pci_data_read(s, addr, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_write[] = {
- &pci_grackle_writeb,
- &pci_grackle_writew,
- &pci_grackle_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_read[] = {
- &pci_grackle_readb,
- &pci_grackle_readw,
- &pci_grackle_readl,
-};
-
-void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque)
-{
- bus->low_set_irq = set_irq;
- bus->irq_opaque = irq_opaque;
-}
-
-/* XXX: we do not simulate the hardware - we rely on the BIOS to
- set correctly for irq line field */
-static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level)
-{
- PCIBus *s = d->bus;
- s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level);
}
-PCIBus *pci_grackle_init(uint32_t base)
+void pci_for_each_device(void (*fn)(PCIDevice *d))
{
- PCIBus *s;
+ PCIBus *bus = first_bus;
PCIDevice *d;
- int pci_mem_config, pci_mem_data;
-
- s = pci_register_bus();
- s->set_irq = pci_set_irq_simple;
-
- pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
- pci_grackle_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
- pci_grackle_write, s);
- cpu_register_physical_memory(base, 0x1000, pci_mem_config);
- cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
- d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice),
- 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x02; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x01;
- d->config[0x0a] = 0x00; // class_sub = host
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x00; // header_type
-
- d->config[0x18] = 0x00; // primary_bus
- d->config[0x19] = 0x01; // secondary_bus
- d->config[0x1a] = 0x00; // subordinate_bus
- d->config[0x1c] = 0x00;
- d->config[0x1d] = 0x00;
-
- d->config[0x20] = 0x00; // memory_base
- d->config[0x21] = 0x00;
- d->config[0x22] = 0x01; // memory_limit
- d->config[0x23] = 0x00;
-
- d->config[0x24] = 0x00; // prefetchable_memory_base
- d->config[0x25] = 0x00;
- d->config[0x26] = 0x00; // prefetchable_memory_limit
- d->config[0x27] = 0x00;
-
-#if 0
- /* PCI2PCI bridge same values as PearPC - check this */
- d->config[0x00] = 0x11; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x04; // class_sub = pci2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x01; // header_type
-
- d->config[0x18] = 0x0; // primary_bus
- d->config[0x19] = 0x1; // secondary_bus
- d->config[0x1a] = 0x1; // subordinate_bus
- d->config[0x1c] = 0x10; // io_base
- d->config[0x1d] = 0x20; // io_limit
-
- d->config[0x20] = 0x80; // memory_base
- d->config[0x21] = 0x80;
- d->config[0x22] = 0x90; // memory_limit
- d->config[0x23] = 0x80;
+ int devfn;
- d->config[0x24] = 0x00; // prefetchable_memory_base
- d->config[0x25] = 0x84;
- d->config[0x26] = 0x00; // prefetchable_memory_limit
- d->config[0x27] = 0x85;
-#endif
- return s;
-}
-
-/* Uninorth PCI host (for all Mac99 and newer machines */
-static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- int i;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- for (i = 11; i < 32; i++) {
- if ((val & (1 << i)) != 0)
- break;
+ if (bus) {
+ for(devfn = 0; devfn < 256; devfn++) {
+ d = bus->devices[devfn];
+ if (d)
+ fn(d);
+ }
}
-#if 0
- s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-#else
- s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11);
-#endif
-}
-
-static uint32_t pci_unin_main_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- int devfn;
-
- devfn = (s->config_reg >> 8) & 0xFF;
- val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
}
-static CPUWriteMemoryFunc *pci_unin_main_config_write[] = {
- &pci_unin_main_config_writel,
- &pci_unin_main_config_writel,
- &pci_unin_main_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_config_read[] = {
- &pci_unin_main_config_readl,
- &pci_unin_main_config_readl,
- &pci_unin_main_config_readl,
-};
-
-static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
+void pci_info(void)
{
- PCIBus *s = opaque;
- pci_data_write(s, addr & 7, val, 1);
-}
-
-static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr & 7, val, 2);
-}
-
-static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr & 7, val, 4);
-}
-
-static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 1);
-
- return val;
-}
-
-static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
-
- return val;
-}
-
-static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_main_write[] = {
- &pci_unin_main_writeb,
- &pci_unin_main_writew,
- &pci_unin_main_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_read[] = {
- &pci_unin_main_readb,
- &pci_unin_main_readw,
- &pci_unin_main_readl,
-};
-
-#if 0
-
-static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- s->config_reg = 0x80000000 | (val & ~0x00000001);
-}
-
-static uint32_t pci_unin_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = (s->config_reg | 0x00000001) & ~0x80000000;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_config_write[] = {
- &pci_unin_config_writel,
- &pci_unin_config_writel,
- &pci_unin_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_config_read[] = {
- &pci_unin_config_readl,
- &pci_unin_config_readl,
- &pci_unin_config_readl,
-};
-
-static void pci_unin_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- pci_data_write(s, addr & 3, val, 1);
-}
-
-static void pci_unin_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr & 3, val, 2);
-}
-
-static void pci_unin_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr & 3, val, 4);
-}
-
-static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 3, 1);
-
- return val;
-}
-
-static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 3, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
-
- return val;
-}
-
-static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 3, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_write[] = {
- &pci_unin_writeb,
- &pci_unin_writew,
- &pci_unin_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_read[] = {
- &pci_unin_readb,
- &pci_unin_readw,
- &pci_unin_readl,
-};
-#endif
-
-PCIBus *pci_pmac_init(void)
-{
- PCIBus *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data;
-
- /* Use values found on a real PowerMac */
- /* Uninorth main bus */
- s = pci_register_bus();
- s->set_irq = pci_set_irq_simple;
-
- pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
- pci_unin_main_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
- pci_unin_main_write, s);
- cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
- s->devfn_min = 11 << 3;
- d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice),
- 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1F; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-
-#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly
- /* pci-to-pci bridge */
- d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
- NULL, NULL);
- d->config[0x00] = 0x11; // vendor_id : TI
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x05; // revision
- d->config[0x0A] = 0x04; // class_sub = pci2pci
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x20; // latency_timer
- d->config[0x0E] = 0x01; // header_type
-
- d->config[0x18] = 0x01; // primary_bus
- d->config[0x19] = 0x02; // secondary_bus
- d->config[0x1A] = 0x02; // subordinate_bus
- d->config[0x1B] = 0x20; // secondary_latency_timer
- d->config[0x1C] = 0x11; // io_base
- d->config[0x1D] = 0x01; // io_limit
- d->config[0x20] = 0x00; // memory_base
- d->config[0x21] = 0x80;
- d->config[0x22] = 0x00; // memory_limit
- d->config[0x23] = 0x80;
- d->config[0x24] = 0x01; // prefetchable_memory_base
- d->config[0x25] = 0x80;
- d->config[0x26] = 0xF1; // prefectchable_memory_limit
- d->config[0x27] = 0x7F;
- // d->config[0x34] = 0xdc // capabilities_pointer
-#endif
-#if 0 // XXX: not needed for now
- /* Uninorth AGP bus */
- s = &pci_bridge[1];
- pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
- pci_unin_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
- pci_unin_write, s);
- cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data);
-
- d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
- NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x20; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- // d->config[0x34] = 0x80; // capabilities_pointer
-#endif
-
-#if 0 // XXX: not needed for now
- /* Uninorth internal bus */
- s = &pci_bridge[2];
- pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
- pci_unin_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
- pci_unin_write, s);
- cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data);
-
- d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
- 3, 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1E; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-#endif
- return s;
-}
-
-/* Ultrasparc APB PCI host */
-static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- int i;
-
- for (i = 11; i < 32; i++) {
- if ((val & (1 << i)) != 0)
- break;
- }
- s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-}
-
-static uint32_t pci_apb_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- int devfn;
-
- devfn = (s->config_reg >> 8) & 0xFF;
- val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_config_write[] = {
- &pci_apb_config_writel,
- &pci_apb_config_writel,
- &pci_apb_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_config_read[] = {
- &pci_apb_config_readl,
- &pci_apb_config_readl,
- &pci_apb_config_readl,
-};
-
-static void apb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- //PCIBus *s = opaque;
-
- switch (addr & 0x3f) {
- case 0x00: // Control/Status
- case 0x10: // AFSR
- case 0x18: // AFAR
- case 0x20: // Diagnostic
- case 0x28: // Target address space
- // XXX
- default:
- break;
- }
-}
-
-static uint32_t apb_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- //PCIBus *s = opaque;
- uint32_t val;
-
- switch (addr & 0x3f) {
- case 0x00: // Control/Status
- case 0x10: // AFSR
- case 0x18: // AFAR
- case 0x20: // Diagnostic
- case 0x28: // Target address space
- // XXX
- default:
- val = 0;
- break;
- }
- return val;
-}
-
-static CPUWriteMemoryFunc *apb_config_write[] = {
- &apb_config_writel,
- &apb_config_writel,
- &apb_config_writel,
-};
-
-static CPUReadMemoryFunc *apb_config_read[] = {
- &apb_config_readl,
- &apb_config_readl,
- &apb_config_readl,
-};
-
-static void pci_apb_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
- pci_data_write(s, addr & 7, val, 1);
-}
-
-static void pci_apb_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
- pci_data_write(s, addr & 7, val, 2);
-}
-
-static void pci_apb_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
- pci_data_write(s, addr & 7, val, 4);
-}
-
-static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 1);
- return val;
-}
-
-static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 2);
- return val;
-}
-
-static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr, 4);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_write[] = {
- &pci_apb_writeb,
- &pci_apb_writew,
- &pci_apb_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_read[] = {
- &pci_apb_readb,
- &pci_apb_readw,
- &pci_apb_readl,
-};
-
-static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outb(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outw(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outl(NULL, addr & 0xffff, val);
-}
-
-static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inb(NULL, addr & 0xffff);
- return val;
-}
-
-static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inw(NULL, addr & 0xffff);
- return val;
-}
-
-static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inl(NULL, addr & 0xffff);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
- &pci_apb_iowriteb,
- &pci_apb_iowritew,
- &pci_apb_iowritel,
-};
-
-static CPUReadMemoryFunc *pci_apb_ioread[] = {
- &pci_apb_ioreadb,
- &pci_apb_ioreadw,
- &pci_apb_ioreadl,
-};
-
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
-{
- PCIBus *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
-
- /* Ultrasparc APB main bus */
- s = pci_register_bus();
- s->set_irq = pci_set_irq_simple;
-
- pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
- pci_apb_config_write, s);
- apb_config = cpu_register_io_memory(0, apb_config_read,
- apb_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
- pci_apb_write, s);
- pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
- pci_apb_iowrite, s);
-
- cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
- cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
- cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
- cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
-
- d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice),
- -1, NULL, NULL);
- d->config[0x00] = 0x8e; // vendor_id : Sun
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x00; // device_id
- d->config[0x03] = 0xa0;
- d->config[0x04] = 0x06; // command = bus master, pci mem
- d->config[0x05] = 0x00;
- d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
- d->config[0x07] = 0x03; // status = medium devsel
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x00; // programming i/f
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- return s;
-}
-
-/***********************************************************/
-/* generic PCI irq support */
-
-/* 0 <= irq_num <= 3. level must be 0 or 1 */
-void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
-{
- PCIBus *bus = pci_dev->bus;
- bus->set_irq(pci_dev, irq_num, level);
-}
-
-/***********************************************************/
-/* monitor info on PCI */
-
-static void pci_info_device(PCIDevice *d)
-{
- int i, class;
- PCIIORegion *r;
-
- term_printf(" Bus %2d, device %3d, function %d:\n",
- d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
- class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE)));
- term_printf(" ");
- switch(class) {
- case 0x0101:
- term_printf("IDE controller");
- break;
- case 0x0200:
- term_printf("Ethernet controller");
- break;
- case 0x0300:
- term_printf("VGA controller");
- break;
- default:
- term_printf("Class %04x", class);
- break;
- }
- term_printf(": PCI device %04x:%04x\n",
- le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))),
- le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID))));
-
- if (d->config[PCI_INTERRUPT_PIN] != 0) {
- term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
- }
- for(i = 0;i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
- if (r->size != 0) {
- term_printf(" BAR%d: ", i);
- if (r->type & PCI_ADDRESS_SPACE_IO) {
- term_printf("I/O at 0x%04x [0x%04x].\n",
- r->addr, r->addr + r->size - 1);
- } else {
- term_printf("32 bit memory at 0x%08x [0x%08x].\n",
- r->addr, r->addr + r->size - 1);
- }
- }
- }
-}
-
-void pci_info(void)
-{
- PCIBus *bus = first_bus;
- PCIDevice *d;
- int devfn;
-
- if (bus) {
- for(devfn = 0; devfn < 256; devfn++) {
- d = bus->devices[devfn];
- if (d)
- pci_info_device(d);
- }
- }
-}
-
-/***********************************************************/
-/* XXX: the following should be moved to the PC BIOS */
-
-static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
-{
- return cpu_inb(NULL, addr);
-}
-
-static void isa_outb(uint32_t val, uint32_t addr)
-{
- cpu_outb(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
-{
- return cpu_inw(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
-{
- cpu_outw(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
-{
- return cpu_inl(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
-{
- cpu_outl(NULL, addr, val);
-}
-
-static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | addr;
- pci_data_write(s, 0, val, 4);
-}
-
-static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- pci_data_write(s, addr & 3, val, 2);
-}
-
-static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- pci_data_write(s, addr & 3, val, 1);
-}
-
-static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | addr;
- return pci_data_read(s, 0, 4);
-}
-
-static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- return pci_data_read(s, addr & 3, 2);
-}
-
-static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- return pci_data_read(s, addr & 3, 1);
-}
-
-static uint32_t pci_bios_io_addr;
-static uint32_t pci_bios_mem_addr;
-/* host irqs corresponding to PCI irqs A-D */
-static uint8_t pci_irqs[4] = { 10, 11, 10, 11 };
-
-static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
-{
- PCIIORegion *r;
- uint16_t cmd;
- uint32_t ofs;
-
- if ( region_num == PCI_ROM_SLOT ) {
- ofs = 0x30;
- }else{
- ofs = 0x10 + region_num * 4;
- }
-
- pci_config_writel(d, ofs, addr);
- r = &d->io_regions[region_num];
-
- /* enable memory mappings */
- cmd = pci_config_readw(d, PCI_COMMAND);
- if ( region_num == PCI_ROM_SLOT )
- cmd |= 2;
- else if (r->type & PCI_ADDRESS_SPACE_IO)
- cmd |= 1;
- else
- cmd |= 2;
- pci_config_writew(d, PCI_COMMAND, cmd);
-}
-
-static void pci_bios_init_device(PCIDevice *d)
-{
- int class;
- PCIIORegion *r;
- uint32_t *paddr;
- int i, pin, pic_irq, vendor_id, device_id;
-
- class = pci_config_readw(d, PCI_CLASS_DEVICE);
- vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
- device_id = pci_config_readw(d, PCI_DEVICE_ID);
- switch(class) {
- case 0x0101:
- if (vendor_id == 0x8086 && device_id == 0x7010) {
- /* PIIX3 IDE */
- pci_config_writew(d, 0x40, 0x8000); // enable IDE0
- pci_config_writew(d, 0x42, 0x8000); // enable IDE1
- goto default_map;
- } else {
- /* IDE: we map it as in ISA mode */
- pci_set_io_region_addr(d, 0, 0x1f0);
- pci_set_io_region_addr(d, 1, 0x3f4);
- pci_set_io_region_addr(d, 2, 0x170);
- pci_set_io_region_addr(d, 3, 0x374);
- }
- break;
- case 0x0680:
- if (vendor_id == 0x8086 && device_id == 0x7113) {
- // PIIX4 ACPI PM
- pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4
- pci_config_writew(d, 0x22, 0x0000);
- goto default_map;
- }
- break;
-
- case 0x0300:
- if (vendor_id != 0x1234)
- goto default_map;
- /* VGA: map frame buffer to default Bochs VBE address */
- pci_set_io_region_addr(d, 0, 0xE0000000);
- break;
-
- case 0x0800:
- /* PIC */
- vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
- device_id = pci_config_readw(d, PCI_DEVICE_ID);
- if (vendor_id == 0x1014) {
- /* IBM */
- if (device_id == 0x0046 || device_id == 0xFFFF) {
- /* MPIC & MPIC2 */
- pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
- }
- }
- break;
- case 0xff00:
- if (vendor_id == 0x0106b &&
- (device_id == 0x0017 || device_id == 0x0022)) {
- /* macio bridge */
- pci_set_io_region_addr(d, 0, 0x80800000);
- }
- break;
- default:
- default_map:
- /* default memory mappings */
- for(i = 0; i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
- if (r->size) {
- if (r->type & PCI_ADDRESS_SPACE_IO)
- paddr = &pci_bios_io_addr;
- else
- paddr = &pci_bios_mem_addr;
- *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
- pci_set_io_region_addr(d, i, *paddr);
- *paddr += r->size;
- }
- }
- break;
- }
-
- /* map the interrupt */
- pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
- if (pin != 0) {
- pin = pci_slot_get_pirq(d, pin - 1);
- pic_irq = pci_irqs[pin];
- pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
- }
- if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) {
- // PIIX4 ACPI PM
- pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4
- pci_config_writew(d, 0x22, 0x0000);
- pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9
- pci_config_writew(d, 0x3d, 0x0001);
- }
-}
-
-/*
- * This function initializes the PCI devices as a normal PCI BIOS
- * would do. It is provided just in case the BIOS has no support for
- * PCI.
- */
-void pci_bios_init(void)
-{
- PCIBus *bus;
- PCIDevice *d;
- int devfn, i, irq;
- uint8_t elcr[2];
-
- pci_bios_io_addr = 0xc000;
- pci_bios_mem_addr = 0xf0000000;
-
- /* activate IRQ mappings */
- elcr[0] = 0x00;
- elcr[1] = 0x00;
- for(i = 0; i < 4; i++) {
- irq = pci_irqs[i];
- /* set to trigger level */
- elcr[irq >> 3] |= (1 << (irq & 7));
- /* activate irq remapping in PIIX */
- pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq);
- }
- isa_outb(elcr[0], 0x4d0);
- isa_outb(elcr[1], 0x4d1);
-
- bus = first_bus;
- if (bus) {
- for(devfn = 0; devfn < 256; devfn++) {
- d = bus->devices[devfn];
- if (d)
- pci_bios_init_device(d);
- }
- }
+ pci_for_each_device(pci_info_device);
}
/* Initialize a PCI NIC. */
pci_ne2000_init(bus, nd);
} else if (strcmp(nd->model, "rtl8139") == 0) {
pci_rtl8139_init(bus, nd);
+ } else if (strcmp(nd->model, "pcnet") == 0) {
+ pci_pcnet_init(bus, nd);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
exit (1);
--- /dev/null
+/*
+ * QEMU Common PCI Host bridge configuration data space access routines.
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Worker routines for a PCI host controller that uses an {address,data}
+ register pair to access PCI configuration space. */
+
+typedef struct {
+ uint32_t config_reg;
+ PCIBus *bus;
+} PCIHostState;
+
+static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
+}
+
+static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
+}
+
+static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg, val, 4);
+}
+
+static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xff;
+ return pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
+}
+
+static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ uint32_t val;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xffff;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ uint32_t val;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xffffffff;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
--- /dev/null
+/*
+ * QEMU AMD PC-Net II (Am79C970A) emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
+ */
+
+#include "vl.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+#define PCNET_IOPORT_SIZE 0x20
+#define PCNET_PNPMMIO_SIZE 0x20
+
+
+typedef struct PCNetState_st PCNetState;
+
+struct PCNetState_st {
+ PCIDevice dev;
+ VLANClientState *vc;
+ NICInfo *nd;
+ QEMUTimer *poll_timer;
+ int mmio_io_addr, rap, isr, lnkst;
+ target_phys_addr_t rdra, tdra;
+ uint8_t prom[16];
+ uint16_t csr[128];
+ uint16_t bcr[32];
+ uint64_t timer;
+ int xmit_pos, recv_pos;
+ uint8_t buffer[4096];
+ int tx_busy;
+};
+
+/* XXX: using bitfields for target memory structures is almost surely
+ not portable, so it should be suppressed ASAP */
+#ifdef __GNUC__
+#define PACKED_FIELD(A) A __attribute__ ((packed))
+#else
+#error FixMe
+#endif
+
+struct qemu_ether_header {
+ uint8_t ether_dhost[6];
+ uint8_t ether_shost[6];
+ uint16_t ether_type;
+};
+
+/* BUS CONFIGURATION REGISTERS */
+#define BCR_MSRDA 0
+#define BCR_MSWRA 1
+#define BCR_MC 2
+#define BCR_LNKST 4
+#define BCR_LED1 5
+#define BCR_LED2 6
+#define BCR_LED3 7
+#define BCR_FDC 9
+#define BCR_BSBC 18
+#define BCR_EECAS 19
+#define BCR_SWS 20
+#define BCR_PLAT 22
+
+#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)
+#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)
+#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF)
+
+#define CSR_INIT(S) !!(((S)->csr[0])&0x0001)
+#define CSR_STRT(S) !!(((S)->csr[0])&0x0002)
+#define CSR_STOP(S) !!(((S)->csr[0])&0x0004)
+#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)
+#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)
+#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)
+#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)
+#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)
+#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)
+#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
+#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)
+#define CSR_SPND(S) !!(((S)->csr[5])&0x0001)
+#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)
+#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)
+#define CSR_DRX(S) !!(((S)->csr[15])&0x0001)
+#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)
+#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)
+#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
+#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
+#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
+
+#define CSR_CRBC(S) ((S)->csr[40])
+#define CSR_CRST(S) ((S)->csr[41])
+#define CSR_CXBC(S) ((S)->csr[42])
+#define CSR_CXST(S) ((S)->csr[43])
+#define CSR_NRBC(S) ((S)->csr[44])
+#define CSR_NRST(S) ((S)->csr[45])
+#define CSR_POLL(S) ((S)->csr[46])
+#define CSR_PINT(S) ((S)->csr[47])
+#define CSR_RCVRC(S) ((S)->csr[72])
+#define CSR_XMTRC(S) ((S)->csr[74])
+#define CSR_RCVRL(S) ((S)->csr[76])
+#define CSR_XMTRL(S) ((S)->csr[78])
+#define CSR_MISSC(S) ((S)->csr[112])
+
+#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16))
+#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16))
+#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16))
+#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16))
+#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16))
+#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16))
+#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16))
+#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16))
+#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16))
+#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16))
+#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16))
+#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16))
+#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16))
+#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16))
+
+#define PHYSADDR(S,A) \
+ (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))
+
+struct pcnet_initblk16 {
+ uint16_t mode;
+ uint16_t padr1;
+ uint16_t padr2;
+ uint16_t padr3;
+ uint16_t ladrf1;
+ uint16_t ladrf2;
+ uint16_t ladrf3;
+ uint16_t ladrf4;
+ unsigned PACKED_FIELD(rdra:24);
+ unsigned PACKED_FIELD(res1:5);
+ unsigned PACKED_FIELD(rlen:3);
+ unsigned PACKED_FIELD(tdra:24);
+ unsigned PACKED_FIELD(res2:5);
+ unsigned PACKED_FIELD(tlen:3);
+};
+
+struct pcnet_initblk32 {
+ uint16_t mode;
+ unsigned PACKED_FIELD(res1:4);
+ unsigned PACKED_FIELD(rlen:4);
+ unsigned PACKED_FIELD(res2:4);
+ unsigned PACKED_FIELD(tlen:4);
+ uint16_t padr1;
+ uint16_t padr2;
+ uint16_t padr3;
+ uint16_t _res;
+ uint16_t ladrf1;
+ uint16_t ladrf2;
+ uint16_t ladrf3;
+ uint16_t ladrf4;
+ uint32_t rdra;
+ uint32_t tdra;
+};
+
+struct pcnet_TMD {
+ struct {
+ unsigned tbadr:32;
+ } tmd0;
+ struct {
+ unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1);
+ unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1);
+ unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1);
+ } tmd1;
+ struct {
+ unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12);
+ unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1);
+ unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1);
+ } tmd2;
+ struct {
+ unsigned res:32;
+ } tmd3;
+};
+
+struct pcnet_RMD {
+ struct {
+ unsigned rbadr:32;
+ } rmd0;
+ struct {
+ unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4);
+ unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1);
+ unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1);
+ unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1);
+ } rmd1;
+ struct {
+ unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4);
+ unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8);
+ } rmd2;
+ struct {
+ unsigned res:32;
+ } rmd3;
+};
+
+
+#define PRINT_TMD(T) printf( \
+ "TMD0 : TBADR=0x%08x\n" \
+ "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
+ "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
+ " BPE=%d, BCNT=%d\n" \
+ "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
+ "LCA=%d, RTR=%d,\n" \
+ " TDR=%d, TRC=%d\n", \
+ (T)->tmd0.tbadr, \
+ (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \
+ (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \
+ (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \
+ 4096-(T)->tmd1.bcnt, \
+ (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
+ (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
+ (T)->tmd2.tdr, (T)->tmd2.trc)
+
+#define PRINT_RMD(R) printf( \
+ "RMD0 : RBADR=0x%08x\n" \
+ "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
+ "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
+ "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
+ "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
+ (R)->rmd0.rbadr, \
+ (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \
+ (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \
+ (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \
+ (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \
+ (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \
+ (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
+ (R)->rmd2.zeros)
+
+static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
+{
+ if (!BCR_SWSTYLE(s)) {
+ uint16_t xda[4];
+ cpu_physical_memory_read(addr,
+ (void *)&xda[0], sizeof(xda));
+ ((uint32_t *)tmd)[0] = (xda[0]&0xffff) |
+ ((xda[1]&0x00ff) << 16);
+ ((uint32_t *)tmd)[1] = (xda[2]&0xffff)|
+ ((xda[1] & 0xff00) << 16);
+ ((uint32_t *)tmd)[2] =
+ (xda[3] & 0xffff) << 16;
+ ((uint32_t *)tmd)[3] = 0;
+ }
+ else
+ if (BCR_SWSTYLE(s) != 3)
+ cpu_physical_memory_read(addr, (void *)tmd, 16);
+ else {
+ uint32_t xda[4];
+ cpu_physical_memory_read(addr,
+ (void *)&xda[0], sizeof(xda));
+ ((uint32_t *)tmd)[0] = xda[2];
+ ((uint32_t *)tmd)[1] = xda[1];
+ ((uint32_t *)tmd)[2] = xda[0];
+ ((uint32_t *)tmd)[3] = xda[3];
+ }
+}
+
+static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
+{
+ if (!BCR_SWSTYLE(s)) {
+ uint16_t xda[4];
+ xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
+ xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) |
+ ((((uint32_t *)tmd)[1]>>16)&0xff00);
+ xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
+ xda[3] = ((uint32_t *)tmd)[2] >> 16;
+ cpu_physical_memory_write(addr,
+ (void *)&xda[0], sizeof(xda));
+ }
+ else {
+ if (BCR_SWSTYLE(s) != 3)
+ cpu_physical_memory_write(addr, (void *)tmd, 16);
+ else {
+ uint32_t xda[4];
+ xda[0] = ((uint32_t *)tmd)[2];
+ xda[1] = ((uint32_t *)tmd)[1];
+ xda[2] = ((uint32_t *)tmd)[0];
+ xda[3] = ((uint32_t *)tmd)[3];
+ cpu_physical_memory_write(addr,
+ (void *)&xda[0], sizeof(xda));
+ }
+ }
+}
+
+static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
+{
+ if (!BCR_SWSTYLE(s)) {
+ uint16_t rda[4];
+ cpu_physical_memory_read(addr,
+ (void *)&rda[0], sizeof(rda));
+ ((uint32_t *)rmd)[0] = (rda[0]&0xffff)|
+ ((rda[1] & 0x00ff) << 16);
+ ((uint32_t *)rmd)[1] = (rda[2]&0xffff)|
+ ((rda[1] & 0xff00) << 16);
+ ((uint32_t *)rmd)[2] = rda[3] & 0xffff;
+ ((uint32_t *)rmd)[3] = 0;
+ }
+ else
+ if (BCR_SWSTYLE(s) != 3)
+ cpu_physical_memory_read(addr, (void *)rmd, 16);
+ else {
+ uint32_t rda[4];
+ cpu_physical_memory_read(addr,
+ (void *)&rda[0], sizeof(rda));
+ ((uint32_t *)rmd)[0] = rda[2];
+ ((uint32_t *)rmd)[1] = rda[1];
+ ((uint32_t *)rmd)[2] = rda[0];
+ ((uint32_t *)rmd)[3] = rda[3];
+ }
+}
+
+static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
+{
+ if (!BCR_SWSTYLE(s)) {
+ uint16_t rda[4]; \
+ rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \
+ rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\
+ ((((uint32_t *)rmd)[1]>>16)&0xff00);\
+ rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \
+ rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \
+ cpu_physical_memory_write(addr, \
+ (void *)&rda[0], sizeof(rda)); \
+ }
+ else {
+ if (BCR_SWSTYLE(s) != 3)
+ cpu_physical_memory_write(addr, (void *)rmd, 16);
+ else {
+ uint32_t rda[4];
+ rda[0] = ((uint32_t *)rmd)[2];
+ rda[1] = ((uint32_t *)rmd)[1];
+ rda[2] = ((uint32_t *)rmd)[0];
+ rda[3] = ((uint32_t *)rmd)[3];
+ cpu_physical_memory_write(addr,
+ (void *)&rda[0], sizeof(rda));
+ }
+ }
+}
+
+
+#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
+
+#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
+
+#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
+
+#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
+
+#if 1
+
+#define CHECK_RMD(ADDR,RES) do { \
+ struct pcnet_RMD rmd; \
+ RMDLOAD(&rmd,(ADDR)); \
+ (RES) |= (rmd.rmd1.ones != 15) \
+ || (rmd.rmd2.zeros != 0); \
+} while (0)
+
+#define CHECK_TMD(ADDR,RES) do { \
+ struct pcnet_TMD tmd; \
+ TMDLOAD(&tmd,(ADDR)); \
+ (RES) |= (tmd.tmd1.ones != 15); \
+} while (0)
+
+#else
+
+#define CHECK_RMD(ADDR,RES) do { \
+ switch (BCR_SWSTYLE(s)) { \
+ case 0x00: \
+ do { \
+ uint16_t rda[4]; \
+ cpu_physical_memory_read((ADDR), \
+ (void *)&rda[0], sizeof(rda)); \
+ (RES) |= (rda[2] & 0xf000)!=0xf000; \
+ (RES) |= (rda[3] & 0xf000)!=0x0000; \
+ } while (0); \
+ break; \
+ case 0x01: \
+ case 0x02: \
+ do { \
+ uint32_t rda[4]; \
+ cpu_physical_memory_read((ADDR), \
+ (void *)&rda[0], sizeof(rda)); \
+ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
+ (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
+ } while (0); \
+ break; \
+ case 0x03: \
+ do { \
+ uint32_t rda[4]; \
+ cpu_physical_memory_read((ADDR), \
+ (void *)&rda[0], sizeof(rda)); \
+ (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
+ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
+ } while (0); \
+ break; \
+ } \
+} while (0)
+
+#define CHECK_TMD(ADDR,RES) do { \
+ switch (BCR_SWSTYLE(s)) { \
+ case 0x00: \
+ do { \
+ uint16_t xda[4]; \
+ cpu_physical_memory_read((ADDR), \
+ (void *)&xda[0], sizeof(xda)); \
+ (RES) |= (xda[2] & 0xf000)!=0xf000;\
+ } while (0); \
+ break; \
+ case 0x01: \
+ case 0x02: \
+ case 0x03: \
+ do { \
+ uint32_t xda[4]; \
+ cpu_physical_memory_read((ADDR), \
+ (void *)&xda[0], sizeof(xda)); \
+ (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
+ } while (0); \
+ break; \
+ } \
+} while (0)
+
+#endif
+
+#define PRINT_PKTHDR(BUF) do { \
+ struct qemu_ether_header *hdr = (void *)(BUF); \
+ printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+ "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+ "type=0x%04x (bcast=%d)\n", \
+ hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
+ hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
+ hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
+ hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
+ be16_to_cpu(hdr->ether_type), \
+ !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \
+} while (0)
+
+#define MULTICAST_FILTER_LEN 8
+
+static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
+{
+#define LNC_POLYNOMIAL 0xEDB88320UL
+ uint32_t crc = 0xFFFFFFFF;
+ int idx, bit;
+ uint8_t data;
+
+ for (idx = 0; idx < 6; idx++) {
+ for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
+ data >>= 1;
+ }
+ }
+ return crc;
+#undef LNC_POLYNOMIAL
+}
+
+#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
+
+/* generated using the AUTODIN II polynomial
+ * x^32 + x^26 + x^23 + x^22 + x^16 +
+ * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+ */
+static const uint32_t crctab[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
+{
+ struct qemu_ether_header *hdr = (void *)buf;
+ uint8_t padr[6] = {
+ s->csr[12] & 0xff, s->csr[12] >> 8,
+ s->csr[13] & 0xff, s->csr[13] >> 8,
+ s->csr[14] & 0xff, s->csr[14] >> 8
+ };
+ int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
+#ifdef PCNET_DEBUG_MATCH
+ printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
+ "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
+ hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
+ padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
+ printf("padr_match result=%d\n", result);
+#endif
+ return result;
+}
+
+static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
+{
+ static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct qemu_ether_header *hdr = (void *)buf;
+ int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
+#ifdef PCNET_DEBUG_MATCH
+ printf("padr_bcast result=%d\n", result);
+#endif
+ return result;
+}
+
+static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
+{
+ struct qemu_ether_header *hdr = (void *)buf;
+ if ((*(hdr->ether_dhost)&0x01) &&
+ ((uint64_t *)&s->csr[8])[0] != 0LL) {
+ uint8_t ladr[8] = {
+ s->csr[8] & 0xff, s->csr[8] >> 8,
+ s->csr[9] & 0xff, s->csr[9] >> 8,
+ s->csr[10] & 0xff, s->csr[10] >> 8,
+ s->csr[11] & 0xff, s->csr[11] >> 8
+ };
+ int index = lnc_mchash(hdr->ether_dhost) >> 26;
+ return !!(ladr[index >> 3] & (1 << (index & 7)));
+ }
+ return 0;
+}
+
+static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
+{
+ while (idx < 1) idx += CSR_RCVRL(s);
+ return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
+}
+
+static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
+{
+ int64_t next_time = current_time +
+ muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
+ ticks_per_sec, 33000000L);
+ if (next_time <= current_time)
+ next_time = current_time + 1;
+ return next_time;
+}
+
+static void pcnet_poll(PCNetState *s);
+static void pcnet_poll_timer(void *opaque);
+
+static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
+static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
+static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
+static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
+
+static void pcnet_s_reset(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+ printf("pcnet_s_reset\n");
+#endif
+
+ s->lnkst = 0x40;
+ s->rdra = 0;
+ s->tdra = 0;
+ s->rap = 0;
+
+ s->bcr[BCR_BSBC] &= ~0x0080;
+
+ s->csr[0] = 0x0004;
+ s->csr[3] = 0x0000;
+ s->csr[4] = 0x0115;
+ s->csr[5] = 0x0000;
+ s->csr[6] = 0x0000;
+ s->csr[8] = 0;
+ s->csr[9] = 0;
+ s->csr[10] = 0;
+ s->csr[11] = 0;
+ s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
+ s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
+ s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
+ s->csr[15] &= 0x21c4;
+ s->csr[72] = 1;
+ s->csr[74] = 1;
+ s->csr[76] = 1;
+ s->csr[78] = 1;
+ s->csr[80] = 0x1410;
+ s->csr[88] = 0x1003;
+ s->csr[89] = 0x0262;
+ s->csr[94] = 0x0000;
+ s->csr[100] = 0x0200;
+ s->csr[103] = 0x0105;
+ s->csr[103] = 0x0105;
+ s->csr[112] = 0x0000;
+ s->csr[114] = 0x0000;
+ s->csr[122] = 0x0000;
+ s->csr[124] = 0x0000;
+
+ s->tx_busy = 0;
+}
+
+static void pcnet_update_irq(PCNetState *s)
+{
+ int isr = 0;
+ s->csr[0] &= ~0x0080;
+
+#if 1
+ if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
+ (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
+ (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
+#else
+ if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
+ (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
+ (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
+ (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
+ (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
+ (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
+ (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
+ (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
+ (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
+ (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
+ (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
+ (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
+#endif
+ {
+
+ isr = CSR_INEA(s);
+ s->csr[0] |= 0x0080;
+ }
+
+ if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
+ s->csr[4] &= ~0x0080;
+ s->csr[4] |= 0x0040;
+ s->csr[0] |= 0x0080;
+ isr = 1;
+#ifdef PCNET_DEBUG
+ printf("pcnet user int\n");
+#endif
+ }
+
+#if 1
+ if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
+#else
+ if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
+ (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
+#endif
+ {
+ isr = 1;
+ s->csr[0] |= 0x0080;
+ }
+
+ if (isr != s->isr) {
+#ifdef PCNET_DEBUG
+ printf("pcnet: INTA=%d\n", isr);
+#endif
+ }
+ pci_set_irq(&s->dev, 0, isr);
+ s->isr = isr;
+}
+
+static void pcnet_init(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+ printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
+#endif
+
+#define PCNET_INIT() do { \
+ cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \
+ (uint8_t *)&initblk, sizeof(initblk)); \
+ s->csr[15] = le16_to_cpu(initblk.mode); \
+ CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
+ CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
+ s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
+ s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \
+ s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \
+ s->csr[10] = le16_to_cpu(initblk.ladrf3); \
+ s->csr[11] = le16_to_cpu(initblk.ladrf4); \
+ s->csr[12] = le16_to_cpu(initblk.padr1); \
+ s->csr[13] = le16_to_cpu(initblk.padr2); \
+ s->csr[14] = le16_to_cpu(initblk.padr3); \
+ s->rdra = PHYSADDR(s,initblk.rdra); \
+ s->tdra = PHYSADDR(s,initblk.tdra); \
+} while (0)
+
+ if (BCR_SSIZE32(s)) {
+ struct pcnet_initblk32 initblk;
+ PCNET_INIT();
+#ifdef PCNET_DEBUG
+ printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
+ initblk.rlen, initblk.tlen);
+#endif
+ } else {
+ struct pcnet_initblk16 initblk;
+ PCNET_INIT();
+#ifdef PCNET_DEBUG
+ printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
+ initblk.rlen, initblk.tlen);
+#endif
+ }
+
+#undef PCNET_INIT
+
+ CSR_RCVRC(s) = CSR_RCVRL(s);
+ CSR_XMTRC(s) = CSR_XMTRL(s);
+
+#ifdef PCNET_DEBUG
+ printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
+ BCR_SSIZE32(s),
+ s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
+#endif
+
+ s->csr[0] |= 0x0101;
+ s->csr[0] &= ~0x0004; /* clear STOP bit */
+}
+
+static void pcnet_start(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+ printf("pcnet_start\n");
+#endif
+
+ if (!CSR_DTX(s))
+ s->csr[0] |= 0x0010; /* set TXON */
+
+ if (!CSR_DRX(s))
+ s->csr[0] |= 0x0020; /* set RXON */
+
+ s->csr[0] &= ~0x0004; /* clear STOP bit */
+ s->csr[0] |= 0x0002;
+}
+
+static void pcnet_stop(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+ printf("pcnet_stop\n");
+#endif
+ s->csr[0] &= ~0x7feb;
+ s->csr[0] |= 0x0014;
+ s->csr[4] &= ~0x02c2;
+ s->csr[5] &= ~0x0011;
+ pcnet_poll_timer(s);
+}
+
+static void pcnet_rdte_poll(PCNetState *s)
+{
+ s->csr[28] = s->csr[29] = 0;
+ if (s->rdra) {
+ int bad = 0;
+#if 1
+ target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
+ target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
+ target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
+#else
+ target_phys_addr_t crda = s->rdra +
+ (CSR_RCVRL(s) - CSR_RCVRC(s)) *
+ (BCR_SWSTYLE(s) ? 16 : 8 );
+ int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
+ target_phys_addr_t nrda = s->rdra +
+ (CSR_RCVRL(s) - nrdc) *
+ (BCR_SWSTYLE(s) ? 16 : 8 );
+ int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
+ target_phys_addr_t nnrd = s->rdra +
+ (CSR_RCVRL(s) - nnrc) *
+ (BCR_SWSTYLE(s) ? 16 : 8 );
+#endif
+
+ CHECK_RMD(PHYSADDR(s,crda), bad);
+ if (!bad) {
+ CHECK_RMD(PHYSADDR(s,nrda), bad);
+ if (bad || (nrda == crda)) nrda = 0;
+ CHECK_RMD(PHYSADDR(s,nnrd), bad);
+ if (bad || (nnrd == crda)) nnrd = 0;
+
+ s->csr[28] = crda & 0xffff;
+ s->csr[29] = crda >> 16;
+ s->csr[26] = nrda & 0xffff;
+ s->csr[27] = nrda >> 16;
+ s->csr[36] = nnrd & 0xffff;
+ s->csr[37] = nnrd >> 16;
+#ifdef PCNET_DEBUG
+ if (bad) {
+ printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n",
+ PHYSADDR(s,crda));
+ }
+ } else {
+ printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda));
+#endif
+ }
+ }
+
+ if (CSR_CRDA(s)) {
+ struct pcnet_RMD rmd;
+ RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
+ CSR_CRBC(s) = rmd.rmd1.bcnt;
+ CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+#ifdef PCNET_DEBUG_RMD_X
+ printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
+ PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
+ ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
+ PRINT_RMD(&rmd);
+#endif
+ } else {
+ CSR_CRBC(s) = CSR_CRST(s) = 0;
+ }
+
+ if (CSR_NRDA(s)) {
+ struct pcnet_RMD rmd;
+ RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
+ CSR_NRBC(s) = rmd.rmd1.bcnt;
+ CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+ } else {
+ CSR_NRBC(s) = CSR_NRST(s) = 0;
+ }
+
+}
+
+static int pcnet_tdte_poll(PCNetState *s)
+{
+ s->csr[34] = s->csr[35] = 0;
+ if (s->tdra) {
+ target_phys_addr_t cxda = s->tdra +
+ (CSR_XMTRL(s) - CSR_XMTRC(s)) *
+ (BCR_SWSTYLE(s) ? 16 : 8 );
+ int bad = 0;
+ CHECK_TMD(PHYSADDR(s, cxda),bad);
+ if (!bad) {
+ if (CSR_CXDA(s) != cxda) {
+ s->csr[60] = s->csr[34];
+ s->csr[61] = s->csr[35];
+ s->csr[62] = CSR_CXBC(s);
+ s->csr[63] = CSR_CXST(s);
+ }
+ s->csr[34] = cxda & 0xffff;
+ s->csr[35] = cxda >> 16;
+#ifdef PCNET_DEBUG
+ } else {
+ printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
+#endif
+ }
+ }
+
+ if (CSR_CXDA(s)) {
+ struct pcnet_TMD tmd;
+
+ TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
+ CSR_CXBC(s) = tmd.tmd1.bcnt;
+ CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
+ } else {
+ CSR_CXBC(s) = CSR_CXST(s) = 0;
+ }
+
+ return !!(CSR_CXST(s) & 0x8000);
+}
+
+static int pcnet_can_receive(void *opaque)
+{
+ PCNetState *s = opaque;
+ if (CSR_STOP(s) || CSR_SPND(s))
+ return 0;
+
+ if (s->recv_pos > 0)
+ return 0;
+
+ return sizeof(s->buffer)-16;
+}
+
+#define MIN_BUF_SIZE 60
+
+static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
+{
+ PCNetState *s = opaque;
+ int is_padr = 0, is_bcast = 0, is_ladr = 0;
+ uint8_t buf1[60];
+
+ if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
+ return;
+
+#ifdef PCNET_DEBUG
+ printf("pcnet_receive size=%d\n", size);
+#endif
+
+ /* if too small buffer, then expand it */
+ if (size < MIN_BUF_SIZE) {
+ memcpy(buf1, buf, size);
+ memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+ buf = buf1;
+ size = MIN_BUF_SIZE;
+ }
+
+ if (CSR_PROM(s)
+ || (is_padr=padr_match(s, buf, size))
+ || (is_bcast=padr_bcast(s, buf, size))
+ || (is_ladr=ladr_match(s, buf, size))) {
+
+ pcnet_rdte_poll(s);
+
+ if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
+ struct pcnet_RMD rmd;
+ int rcvrc = CSR_RCVRC(s)-1,i;
+ target_phys_addr_t nrda;
+ for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
+ if (rcvrc <= 1)
+ rcvrc = CSR_RCVRL(s);
+ nrda = s->rdra +
+ (CSR_RCVRL(s) - rcvrc) *
+ (BCR_SWSTYLE(s) ? 16 : 8 );
+ RMDLOAD(&rmd, PHYSADDR(s,nrda));
+ if (rmd.rmd1.own) {
+#ifdef PCNET_DEBUG_RMD
+ printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
+ rcvrc, CSR_RCVRC(s));
+#endif
+ CSR_RCVRC(s) = rcvrc;
+ pcnet_rdte_poll(s);
+ break;
+ }
+ }
+ }
+
+ if (!(CSR_CRST(s) & 0x8000)) {
+#ifdef PCNET_DEBUG_RMD
+ printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
+#endif
+ s->csr[0] |= 0x1000; /* Set MISS flag */
+ CSR_MISSC(s)++;
+ } else {
+ uint8_t *src = &s->buffer[8];
+ target_phys_addr_t crda = CSR_CRDA(s);
+ struct pcnet_RMD rmd;
+ int pktcount = 0;
+
+ memcpy(src, buf, size);
+
+#if 1
+ /* no need to compute the CRC */
+ src[size] = 0;
+ src[size + 1] = 0;
+ src[size + 2] = 0;
+ src[size + 3] = 0;
+ size += 4;
+#else
+ /* XXX: avoid CRC generation */
+ if (!CSR_ASTRP_RCV(s)) {
+ uint32_t fcs = ~0;
+ uint8_t *p = src;
+
+ while (size < 46) {
+ src[size++] = 0;
+ }
+
+ while (p != &src[size]) {
+ CRC(fcs, *p++);
+ }
+ ((uint32_t *)&src[size])[0] = htonl(fcs);
+ size += 4; /* FCS at end of packet */
+ } else size += 4;
+#endif
+
+#ifdef PCNET_DEBUG_MATCH
+ PRINT_PKTHDR(buf);
+#endif
+
+ RMDLOAD(&rmd, PHYSADDR(s,crda));
+ /*if (!CSR_LAPPEN(s))*/
+ rmd.rmd1.stp = 1;
+
+#define PCNET_RECV_STORE() do { \
+ int count = MIN(4096 - rmd.rmd1.bcnt,size); \
+ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \
+ cpu_physical_memory_write(rbadr, src, count); \
+ src += count; size -= count; \
+ rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
+ RMDSTORE(&rmd, PHYSADDR(s,crda)); \
+ pktcount++; \
+} while (0)
+
+ PCNET_RECV_STORE();
+ if ((size > 0) && CSR_NRDA(s)) {
+ target_phys_addr_t nrda = CSR_NRDA(s);
+ RMDLOAD(&rmd, PHYSADDR(s,nrda));
+ if (rmd.rmd1.own) {
+ crda = nrda;
+ PCNET_RECV_STORE();
+ if ((size > 0) && (nrda=CSR_NNRD(s))) {
+ RMDLOAD(&rmd, PHYSADDR(s,nrda));
+ if (rmd.rmd1.own) {
+ crda = nrda;
+ PCNET_RECV_STORE();
+ }
+ }
+ }
+ }
+
+#undef PCNET_RECV_STORE
+
+ RMDLOAD(&rmd, PHYSADDR(s,crda));
+ if (size == 0) {
+ rmd.rmd1.enp = 1;
+ rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
+ rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
+ rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
+ } else {
+ rmd.rmd1.oflo = 1;
+ rmd.rmd1.buff = 1;
+ rmd.rmd1.err = 1;
+ }
+ RMDSTORE(&rmd, PHYSADDR(s,crda));
+ s->csr[0] |= 0x0400;
+
+#ifdef PCNET_DEBUG
+ printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
+ CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
+#endif
+#ifdef PCNET_DEBUG_RMD
+ PRINT_RMD(&rmd);
+#endif
+
+ while (pktcount--) {
+ if (CSR_RCVRC(s) <= 1)
+ CSR_RCVRC(s) = CSR_RCVRL(s);
+ else
+ CSR_RCVRC(s)--;
+ }
+
+ pcnet_rdte_poll(s);
+
+ }
+ }
+
+ pcnet_poll(s);
+ pcnet_update_irq(s);
+}
+
+static void pcnet_transmit(PCNetState *s)
+{
+ target_phys_addr_t xmit_cxda = 0;
+ int count = CSR_XMTRL(s)-1;
+ s->xmit_pos = -1;
+
+ if (!CSR_TXON(s)) {
+ s->csr[0] &= ~0x0008;
+ return;
+ }
+
+ s->tx_busy = 1;
+
+ txagain:
+ if (pcnet_tdte_poll(s)) {
+ struct pcnet_TMD tmd;
+
+ TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
+#ifdef PCNET_DEBUG_TMD
+ printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
+ PRINT_TMD(&tmd);
+#endif
+ if (tmd.tmd1.stp) {
+ s->xmit_pos = 0;
+ if (!tmd.tmd1.enp) {
+ cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
+ s->buffer, 4096 - tmd.tmd1.bcnt);
+ s->xmit_pos += 4096 - tmd.tmd1.bcnt;
+ }
+ xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
+ }
+ if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
+ cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
+ s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
+ s->xmit_pos += 4096 - tmd.tmd1.bcnt;
+#ifdef PCNET_DEBUG
+ printf("pcnet_transmit size=%d\n", s->xmit_pos);
+#endif
+ if (CSR_LOOP(s))
+ pcnet_receive(s, s->buffer, s->xmit_pos);
+ else
+ qemu_send_packet(s->vc, s->buffer, s->xmit_pos);
+
+ s->csr[0] &= ~0x0008; /* clear TDMD */
+ s->csr[4] |= 0x0004; /* set TXSTRT */
+ s->xmit_pos = -1;
+ }
+
+ tmd.tmd1.own = 0;
+ TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+ if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
+ s->csr[0] |= 0x0200; /* set TINT */
+
+ if (CSR_XMTRC(s)<=1)
+ CSR_XMTRC(s) = CSR_XMTRL(s);
+ else
+ CSR_XMTRC(s)--;
+ if (count--)
+ goto txagain;
+
+ } else
+ if (s->xmit_pos >= 0) {
+ struct pcnet_TMD tmd;
+ TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
+ tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
+ tmd.tmd1.own = 0;
+ TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
+ s->csr[0] |= 0x0200; /* set TINT */
+ if (!CSR_DXSUFLO(s)) {
+ s->csr[0] &= ~0x0010;
+ } else
+ if (count--)
+ goto txagain;
+ }
+
+ s->tx_busy = 0;
+}
+
+static void pcnet_poll(PCNetState *s)
+{
+ if (CSR_RXON(s)) {
+ pcnet_rdte_poll(s);
+ }
+
+ if (CSR_TDMD(s) ||
+ (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
+ {
+ /* prevent recursion */
+ if (s->tx_busy)
+ return;
+
+ pcnet_transmit(s);
+ }
+}
+
+static void pcnet_poll_timer(void *opaque)
+{
+ PCNetState *s = opaque;
+
+ qemu_del_timer(s->poll_timer);
+
+ if (CSR_TDMD(s)) {
+ pcnet_transmit(s);
+ }
+
+ pcnet_update_irq(s);
+
+ if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
+ uint64_t now = qemu_get_clock(vm_clock) * 33;
+ if (!s->timer || !now)
+ s->timer = now;
+ else {
+ uint64_t t = now - s->timer + CSR_POLL(s);
+ if (t > 0xffffLL) {
+ pcnet_poll(s);
+ CSR_POLL(s) = CSR_PINT(s);
+ } else
+ CSR_POLL(s) = t;
+ }
+ qemu_mod_timer(s->poll_timer,
+ pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock)));
+ }
+}
+
+
+static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
+{
+ uint16_t val = new_value;
+#ifdef PCNET_DEBUG_CSR
+ printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
+#endif
+ switch (rap) {
+ case 0:
+ s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
+
+ s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
+
+ val = (val & 0x007f) | (s->csr[0] & 0x7f00);
+
+ /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
+ if ((val&7) == 7)
+ val &= ~3;
+
+ if (!CSR_STOP(s) && (val & 4))
+ pcnet_stop(s);
+
+ if (!CSR_INIT(s) && (val & 1))
+ pcnet_init(s);
+
+ if (!CSR_STRT(s) && (val & 2))
+ pcnet_start(s);
+
+ if (CSR_TDMD(s))
+ pcnet_transmit(s);
+
+ return;
+ case 1:
+ case 2:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 18: /* CRBAL */
+ case 19: /* CRBAU */
+ case 20: /* CXBAL */
+ case 21: /* CXBAU */
+ case 22: /* NRBAU */
+ case 23: /* NRBAU */
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40: /* CRBC */
+ case 41:
+ case 42: /* CXBC */
+ case 43:
+ case 44:
+ case 45:
+ case 46: /* POLL */
+ case 47: /* POLLINT */
+ case 72:
+ case 74:
+ case 76: /* RCVRL */
+ case 78: /* XMTRL */
+ case 112:
+ if (CSR_STOP(s) || CSR_SPND(s))
+ break;
+ return;
+ case 3:
+ break;
+ case 4:
+ s->csr[4] &= ~(val & 0x026a);
+ val &= ~0x026a; val |= s->csr[4] & 0x026a;
+ break;
+ case 5:
+ s->csr[5] &= ~(val & 0x0a90);
+ val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
+ break;
+ case 16:
+ pcnet_csr_writew(s,1,val);
+ return;
+ case 17:
+ pcnet_csr_writew(s,2,val);
+ return;
+ case 58:
+ pcnet_bcr_writew(s,BCR_SWS,val);
+ break;
+ default:
+ return;
+ }
+ s->csr[rap] = val;
+}
+
+static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
+{
+ uint32_t val;
+ switch (rap) {
+ case 0:
+ pcnet_update_irq(s);
+ val = s->csr[0];
+ val |= (val & 0x7800) ? 0x8000 : 0;
+ break;
+ case 16:
+ return pcnet_csr_readw(s,1);
+ case 17:
+ return pcnet_csr_readw(s,2);
+ case 58:
+ return pcnet_bcr_readw(s,BCR_SWS);
+ case 88:
+ val = s->csr[89];
+ val <<= 16;
+ val |= s->csr[88];
+ break;
+ default:
+ val = s->csr[rap];
+ }
+#ifdef PCNET_DEBUG_CSR
+ printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
+#endif
+ return val;
+}
+
+static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
+{
+ rap &= 127;
+#ifdef PCNET_DEBUG_BCR
+ printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
+#endif
+ switch (rap) {
+ case BCR_SWS:
+ if (!(CSR_STOP(s) || CSR_SPND(s)))
+ return;
+ val &= ~0x0300;
+ switch (val & 0x00ff) {
+ case 0:
+ val |= 0x0200;
+ break;
+ case 1:
+ val |= 0x0100;
+ break;
+ case 2:
+ case 3:
+ val |= 0x0300;
+ break;
+ default:
+ printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
+ val = 0x0200;
+ break;
+ }
+#ifdef PCNET_DEBUG
+ printf("BCR_SWS=0x%04x\n", val);
+#endif
+ case BCR_LNKST:
+ case BCR_LED1:
+ case BCR_LED2:
+ case BCR_LED3:
+ case BCR_MC:
+ case BCR_FDC:
+ case BCR_BSBC:
+ case BCR_EECAS:
+ case BCR_PLAT:
+ s->bcr[rap] = val;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
+{
+ uint32_t val;
+ rap &= 127;
+ switch (rap) {
+ case BCR_LNKST:
+ case BCR_LED1:
+ case BCR_LED2:
+ case BCR_LED3:
+ val = s->bcr[rap] & ~0x8000;
+ val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
+ break;
+ default:
+ val = rap < 32 ? s->bcr[rap] : 0;
+ break;
+ }
+#ifdef PCNET_DEBUG_BCR
+ printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
+#endif
+ return val;
+}
+
+static void pcnet_h_reset(PCNetState *s)
+{
+ int i;
+ uint16_t checksum;
+
+ /* Initialize the PROM */
+
+ memcpy(s->prom, s->nd->macaddr, 6);
+ s->prom[12] = s->prom[13] = 0x00;
+ s->prom[14] = s->prom[15] = 0x57;
+
+ for (i = 0,checksum = 0; i < 16; i++)
+ checksum += s->prom[i];
+ *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
+
+
+ s->bcr[BCR_MSRDA] = 0x0005;
+ s->bcr[BCR_MSWRA] = 0x0005;
+ s->bcr[BCR_MC ] = 0x0002;
+ s->bcr[BCR_LNKST] = 0x00c0;
+ s->bcr[BCR_LED1 ] = 0x0084;
+ s->bcr[BCR_LED2 ] = 0x0088;
+ s->bcr[BCR_LED3 ] = 0x0090;
+ s->bcr[BCR_FDC ] = 0x0000;
+ s->bcr[BCR_BSBC ] = 0x9001;
+ s->bcr[BCR_EECAS] = 0x0002;
+ s->bcr[BCR_SWS ] = 0x0200;
+ s->bcr[BCR_PLAT ] = 0xff06;
+
+ pcnet_s_reset(s);
+}
+
+static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCNetState *s = opaque;
+#ifdef PCNET_DEBUG
+ printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+ /* Check APROMWE bit to enable write access */
+ if (pcnet_bcr_readw(s,2) & 0x80)
+ s->prom[addr & 15] = val;
+}
+
+static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
+{
+ PCNetState *s = opaque;
+ uint32_t val = s->prom[addr &= 15];
+#ifdef PCNET_DEBUG
+ printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+ return val;
+}
+
+static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCNetState *s = opaque;
+ pcnet_poll_timer(s);
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
+#endif
+ if (!BCR_DWIO(s)) {
+ switch (addr & 0x0f) {
+ case 0x00: /* RDP */
+ pcnet_csr_writew(s, s->rap, val);
+ break;
+ case 0x02:
+ s->rap = val & 0x7f;
+ break;
+ case 0x06:
+ pcnet_bcr_writew(s, s->rap, val);
+ break;
+ }
+ }
+ pcnet_update_irq(s);
+}
+
+static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
+{
+ PCNetState *s = opaque;
+ uint32_t val = -1;
+ pcnet_poll_timer(s);
+ if (!BCR_DWIO(s)) {
+ switch (addr & 0x0f) {
+ case 0x00: /* RDP */
+ val = pcnet_csr_readw(s, s->rap);
+ break;
+ case 0x02:
+ val = s->rap;
+ break;
+ case 0x04:
+ pcnet_s_reset(s);
+ val = 0;
+ break;
+ case 0x06:
+ val = pcnet_bcr_readw(s, s->rap);
+ break;
+ }
+ }
+ pcnet_update_irq(s);
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
+#endif
+ return val;
+}
+
+static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCNetState *s = opaque;
+ pcnet_poll_timer(s);
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+ if (BCR_DWIO(s)) {
+ switch (addr & 0x0f) {
+ case 0x00: /* RDP */
+ pcnet_csr_writew(s, s->rap, val & 0xffff);
+ break;
+ case 0x04:
+ s->rap = val & 0x7f;
+ break;
+ case 0x0c:
+ pcnet_bcr_writew(s, s->rap, val & 0xffff);
+ break;
+ }
+ } else
+ if ((addr & 0x0f) == 0) {
+ /* switch device to dword i/o mode */
+ pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
+#ifdef PCNET_DEBUG_IO
+ printf("device switched into dword i/o mode\n");
+#endif
+ }
+ pcnet_update_irq(s);
+}
+
+static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
+{
+ PCNetState *s = opaque;
+ uint32_t val = -1;
+ pcnet_poll_timer(s);
+ if (BCR_DWIO(s)) {
+ switch (addr & 0x0f) {
+ case 0x00: /* RDP */
+ val = pcnet_csr_readw(s, s->rap);
+ break;
+ case 0x04:
+ val = s->rap;
+ break;
+ case 0x08:
+ pcnet_s_reset(s);
+ val = 0;
+ break;
+ case 0x0c:
+ val = pcnet_bcr_readw(s, s->rap);
+ break;
+ }
+ }
+ pcnet_update_irq(s);
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+ return val;
+}
+
+static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ PCNetState *d = (PCNetState *)pci_dev;
+
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);
+#endif
+
+ register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
+ register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+
+ register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
+ register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
+ register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
+ register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+}
+
+static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+ if (!(addr & 0x10))
+ pcnet_aprom_writeb(d, addr & 0x0f, val);
+}
+
+static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+ PCNetState *d = opaque;
+ uint32_t val = -1;
+ if (!(addr & 0x10))
+ val = pcnet_aprom_readb(d, addr & 0x0f);
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff);
+#endif
+ return val;
+}
+
+static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val);
+#endif
+ if (addr & 0x10)
+ pcnet_ioport_writew(d, addr & 0x0f, val);
+ else {
+ addr &= 0x0f;
+ pcnet_aprom_writeb(d, addr, val & 0xff);
+ pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+ }
+}
+
+static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+ PCNetState *d = opaque;
+ uint32_t val = -1;
+ if (addr & 0x10)
+ val = pcnet_ioport_readw(d, addr & 0x0f);
+ else {
+ addr &= 0x0f;
+ val = pcnet_aprom_readb(d, addr+1);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr);
+ }
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff);
+#endif
+ return val;
+}
+
+static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+ if (addr & 0x10)
+ pcnet_ioport_writel(d, addr & 0x0f, val);
+ else {
+ addr &= 0x0f;
+ pcnet_aprom_writeb(d, addr, val & 0xff);
+ pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+ pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
+ pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
+ }
+}
+
+static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+ PCNetState *d = opaque;
+ uint32_t val;
+ if (addr & 0x10)
+ val = pcnet_ioport_readl(d, addr & 0x0f);
+ else {
+ addr &= 0x0f;
+ val = pcnet_aprom_readb(d, addr+3);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr+2);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr+1);
+ val <<= 8;
+ val |= pcnet_aprom_readb(d, addr);
+ }
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+ return val;
+}
+
+
+static CPUWriteMemoryFunc *pcnet_mmio_write[] = {
+ (CPUWriteMemoryFunc *)&pcnet_mmio_writeb,
+ (CPUWriteMemoryFunc *)&pcnet_mmio_writew,
+ (CPUWriteMemoryFunc *)&pcnet_mmio_writel
+};
+
+static CPUReadMemoryFunc *pcnet_mmio_read[] = {
+ (CPUReadMemoryFunc *)&pcnet_mmio_readb,
+ (CPUReadMemoryFunc *)&pcnet_mmio_readw,
+ (CPUReadMemoryFunc *)&pcnet_mmio_readl
+};
+
+static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ PCNetState *d = (PCNetState *)pci_dev;
+
+#ifdef PCNET_DEBUG_IO
+ printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size);
+#endif
+
+ cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr);
+}
+
+void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
+{
+ PCNetState *d;
+ uint8_t *pci_conf;
+
+#if 0
+ printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
+ sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
+#endif
+
+ d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
+ -1, NULL, NULL);
+
+ pci_conf = d->dev.config;
+
+ *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
+ *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
+ *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
+ *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
+ pci_conf[0x08] = 0x10;
+ pci_conf[0x09] = 0x00;
+ pci_conf[0x0a] = 0x00; // ethernet network controller
+ pci_conf[0x0b] = 0x02;
+ pci_conf[0x0e] = 0x00; // header_type
+
+ *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
+ *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
+
+ pci_conf[0x3d] = 1; // interrupt pin 0
+ pci_conf[0x3e] = 0x06;
+ pci_conf[0x3f] = 0xff;
+
+ /* Handler for memory-mapped I/O */
+ d->mmio_io_addr =
+ cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
+
+ pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
+ PCI_ADDRESS_SPACE_IO, pcnet_ioport_map);
+
+ pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
+ PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
+
+ d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
+
+ d->nd = nd;
+
+ d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
+ pcnet_can_receive, d);
+
+ snprintf(d->vc->info_str, sizeof(d->vc->info_str),
+ "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ d->nd->macaddr[0],
+ d->nd->macaddr[1],
+ d->nd->macaddr[2],
+ d->nd->macaddr[3],
+ d->nd->macaddr[4],
+ d->nd->macaddr[5]);
+
+ pcnet_h_reset(d);
+}
int pcspk_audio_init(AudioState *audio)
{
PCSpkState *s = &pcspk_state;
- audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8};
+ audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
if (!audio) {
AUD_log(s_spk, "No audio state\n");
}
AUD_register_card(audio, s_spk, &s->card);
- s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 0);
+ s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
if (!s->voice) {
AUD_log(s_spk, "Could not open voice\n");
return -1;
--- /dev/null
+/*
+ * CFI parallel flash with AMD command set emulation
+ *
+ * Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
+ * Supported commands/modes are:
+ * - flash read
+ * - flash write
+ * - flash ID read
+ * - sector erase
+ * - chip erase
+ * - unlock bypass command
+ * - CFI queries
+ *
+ * It does not support flash interleaving.
+ * It does not implement boot blocs with reduced size
+ * It does not implement software data protection as found in many real chips
+ * It does not implement erase suspend/resume commands
+ * It does not implement multiple sectors erase
+ */
+
+#include "vl.h"
+
+//#define PFLASH_DEBUG
+#ifdef PFLASH_DEBUG
+#define DPRINTF(fmt, args...) \
+do { \
+ printf("PFLASH: " fmt , ##args); \
+} while (0)
+#else
+#define DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+struct pflash_t {
+ BlockDriverState *bs;
+ target_ulong base;
+ target_ulong sector_len;
+ target_ulong total_len;
+ int width;
+ int wcycle; /* if 0, the flash is read normally */
+ int bypass;
+ int ro;
+ uint8_t cmd;
+ uint8_t status;
+ uint16_t ident[4];
+ uint8_t cfi_len;
+ uint8_t cfi_table[0x52];
+ QEMUTimer *timer;
+ ram_addr_t off;
+ int fl_mem;
+ void *storage;
+};
+
+static void pflash_timer (void *opaque)
+{
+ pflash_t *pfl = opaque;
+
+ DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
+ /* Reset flash */
+ pfl->status ^= 0x80;
+ if (pfl->bypass) {
+ pfl->wcycle = 2;
+ } else {
+ cpu_register_physical_memory(pfl->base, pfl->total_len,
+ pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+ pfl->wcycle = 0;
+ }
+ pfl->cmd = 0;
+}
+
+static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
+{
+ target_ulong boff;
+ uint32_t ret;
+ uint8_t *p;
+
+ DPRINTF("%s: offset %08x\n", __func__, offset);
+ ret = -1;
+ offset -= pfl->base;
+ boff = offset & 0xFF;
+ if (pfl->width == 2)
+ boff = boff >> 1;
+ else if (pfl->width == 4)
+ boff = boff >> 2;
+ switch (pfl->cmd) {
+ default:
+ /* This should never happen : reset state & treat it as a read*/
+ DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
+ pfl->wcycle = 0;
+ pfl->cmd = 0;
+ case 0x80:
+ /* We accept reads during second unlock sequence... */
+ case 0x00:
+ flash_read:
+ /* Flash area read */
+ p = pfl->storage;
+ switch (width) {
+ case 1:
+ ret = p[offset];
+// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
+ break;
+ case 2:
+#if defined(TARGET_WORDS_BIGENDIAN)
+ ret = p[offset] << 8;
+ ret |= p[offset + 1];
+#else
+ ret = p[offset];
+ ret |= p[offset + 1] << 8;
+#endif
+// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
+ break;
+ case 4:
+#if defined(TARGET_WORDS_BIGENDIAN)
+ ret = p[offset] << 24;
+ ret |= p[offset + 1] << 16;
+ ret |= p[offset + 2] << 8;
+ ret |= p[offset + 3];
+#else
+ ret = p[offset];
+ ret |= p[offset + 1] << 8;
+ ret |= p[offset + 1] << 8;
+ ret |= p[offset + 2] << 16;
+ ret |= p[offset + 3] << 24;
+#endif
+// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
+ break;
+ }
+ break;
+ case 0x90:
+ /* flash ID read */
+ switch (boff) {
+ case 0x00:
+ case 0x01:
+ ret = pfl->ident[boff & 0x01];
+ break;
+ case 0x02:
+ ret = 0x00; /* Pretend all sectors are unprotected */
+ break;
+ case 0x0E:
+ case 0x0F:
+ if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
+ goto flash_read;
+ ret = pfl->ident[2 + (boff & 0x01)];
+ break;
+ default:
+ goto flash_read;
+ }
+ DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
+ break;
+ case 0xA0:
+ case 0x10:
+ case 0x30:
+ /* Status register read */
+ ret = pfl->status;
+ DPRINTF("%s: status %x\n", __func__, ret);
+ /* Toggle bit 6 */
+ pfl->status ^= 0x40;
+ break;
+ case 0x98:
+ /* CFI query mode */
+ if (boff > pfl->cfi_len)
+ ret = 0;
+ else
+ ret = pfl->cfi_table[boff];
+ break;
+ }
+
+ return ret;
+}
+
+/* update flash content on disk */
+static void pflash_update(pflash_t *pfl, int offset,
+ int size)
+{
+ int offset_end;
+ if (pfl->bs) {
+ offset_end = offset + size;
+ /* round to sectors */
+ offset = offset >> 9;
+ offset_end = (offset_end + 511) >> 9;
+ bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
+ offset_end - offset);
+ }
+}
+
+static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
+ int width)
+{
+ target_ulong boff;
+ uint8_t *p;
+ uint8_t cmd;
+
+ /* WARNING: when the memory area is in ROMD mode, the offset is a
+ ram offset, not a physical address */
+ if (pfl->wcycle == 0)
+ offset -= (target_ulong)(long)pfl->storage;
+ else
+ offset -= pfl->base;
+
+ cmd = value;
+ DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width);
+ if (pfl->cmd != 0xA0 && cmd == 0xF0) {
+ DPRINTF("%s: flash reset asked (%02x %02x)\n",
+ __func__, pfl->cmd, cmd);
+ goto reset_flash;
+ }
+ /* Set the device in I/O access mode */
+ cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
+ boff = offset & (pfl->sector_len - 1);
+ if (pfl->width == 2)
+ boff = boff >> 1;
+ else if (pfl->width == 4)
+ boff = boff >> 2;
+ switch (pfl->wcycle) {
+ case 0:
+ /* We're in read mode */
+ check_unlock0:
+ if (boff == 0x55 && cmd == 0x98) {
+ enter_CFI_mode:
+ /* Enter CFI query mode */
+ pfl->wcycle = 7;
+ pfl->cmd = 0x98;
+ return;
+ }
+ if (boff != 0x555 || cmd != 0xAA) {
+ DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
+ __func__, boff, cmd, 0x555);
+ goto reset_flash;
+ }
+ DPRINTF("%s: unlock sequence started\n", __func__);
+ break;
+ case 1:
+ /* We started an unlock sequence */
+ check_unlock1:
+ if (boff != 0x2AA || cmd != 0x55) {
+ DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
+ goto reset_flash;
+ }
+ DPRINTF("%s: unlock sequence done\n", __func__);
+ break;
+ case 2:
+ /* We finished an unlock sequence */
+ if (!pfl->bypass && boff != 0x555) {
+ DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
+ goto reset_flash;
+ }
+ switch (cmd) {
+ case 0x20:
+ pfl->bypass = 1;
+ goto do_bypass;
+ case 0x80:
+ case 0x90:
+ case 0xA0:
+ pfl->cmd = cmd;
+ DPRINTF("%s: starting command %02x\n", __func__, cmd);
+ break;
+ default:
+ DPRINTF("%s: unknown command %02x\n", __func__, cmd);
+ goto reset_flash;
+ }
+ break;
+ case 3:
+ switch (pfl->cmd) {
+ case 0x80:
+ /* We need another unlock sequence */
+ goto check_unlock0;
+ case 0xA0:
+ DPRINTF("%s: write data offset %08x %08x %d\n",
+ __func__, offset, value, width);
+ p = pfl->storage;
+ switch (width) {
+ case 1:
+ p[offset] &= value;
+ pflash_update(pfl, offset, 1);
+ break;
+ case 2:
+#if defined(TARGET_WORDS_BIGENDIAN)
+ p[offset] &= value >> 8;
+ p[offset + 1] &= value;
+#else
+ p[offset] &= value;
+ p[offset + 1] &= value >> 8;
+#endif
+ pflash_update(pfl, offset, 2);
+ break;
+ case 4:
+#if defined(TARGET_WORDS_BIGENDIAN)
+ p[offset] &= value >> 24;
+ p[offset + 1] &= value >> 16;
+ p[offset + 2] &= value >> 8;
+ p[offset + 3] &= value;
+#else
+ p[offset] &= value;
+ p[offset + 1] &= value >> 8;
+ p[offset + 2] &= value >> 16;
+ p[offset + 3] &= value >> 24;
+#endif
+ pflash_update(pfl, offset, 4);
+ break;
+ }
+ pfl->status = 0x00 | ~(value & 0x80);
+ /* Let's pretend write is immediate */
+ if (pfl->bypass)
+ goto do_bypass;
+ goto reset_flash;
+ case 0x90:
+ if (pfl->bypass && cmd == 0x00) {
+ /* Unlock bypass reset */
+ goto reset_flash;
+ }
+ /* We can enter CFI query mode from autoselect mode */
+ if (boff == 0x55 && cmd == 0x98)
+ goto enter_CFI_mode;
+ /* No break here */
+ default:
+ DPRINTF("%s: invalid write for command %02x\n",
+ __func__, pfl->cmd);
+ goto reset_flash;
+ }
+ case 4:
+ switch (pfl->cmd) {
+ case 0xA0:
+ /* Ignore writes while flash data write is occuring */
+ /* As we suppose write is immediate, this should never happen */
+ return;
+ case 0x80:
+ goto check_unlock1;
+ default:
+ /* Should never happen */
+ DPRINTF("%s: invalid command state %02x (wc 4)\n",
+ __func__, pfl->cmd);
+ goto reset_flash;
+ }
+ break;
+ case 5:
+ switch (cmd) {
+ case 0x10:
+ if (boff != 0x555) {
+ DPRINTF("%s: chip erase: invalid address %04x\n",
+ __func__, offset);
+ goto reset_flash;
+ }
+ /* Chip erase */
+ DPRINTF("%s: start chip erase\n", __func__);
+ memset(pfl->storage, 0xFF, pfl->total_len);
+ pfl->status = 0x00;
+ pflash_update(pfl, 0, pfl->total_len);
+ /* Let's wait 5 seconds before chip erase is done */
+ qemu_mod_timer(pfl->timer,
+ qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
+ break;
+ case 0x30:
+ /* Sector erase */
+ p = pfl->storage;
+ offset &= ~(pfl->sector_len - 1);
+ DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
+ memset(p + offset, 0xFF, pfl->sector_len);
+ pflash_update(pfl, offset, pfl->sector_len);
+ pfl->status = 0x00;
+ /* Let's wait 1/2 second before sector erase is done */
+ qemu_mod_timer(pfl->timer,
+ qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
+ break;
+ default:
+ DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
+ goto reset_flash;
+ }
+ pfl->cmd = cmd;
+ break;
+ case 6:
+ switch (pfl->cmd) {
+ case 0x10:
+ /* Ignore writes during chip erase */
+ return;
+ case 0x30:
+ /* Ignore writes during sector erase */
+ return;
+ default:
+ /* Should never happen */
+ DPRINTF("%s: invalid command state %02x (wc 6)\n",
+ __func__, pfl->cmd);
+ goto reset_flash;
+ }
+ break;
+ case 7: /* Special value for CFI queries */
+ DPRINTF("%s: invalid write in CFI query mode\n", __func__);
+ goto reset_flash;
+ default:
+ /* Should never happen */
+ DPRINTF("%s: invalid write state (wc 7)\n", __func__);
+ goto reset_flash;
+ }
+ pfl->wcycle++;
+
+ return;
+
+ /* Reset flash */
+ reset_flash:
+ if (pfl->wcycle != 0) {
+ cpu_register_physical_memory(pfl->base, pfl->total_len,
+ pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+ }
+ pfl->bypass = 0;
+ pfl->wcycle = 0;
+ pfl->cmd = 0;
+ return;
+
+ do_bypass:
+ pfl->wcycle = 2;
+ pfl->cmd = 0;
+ return;
+}
+
+
+static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
+{
+ return pflash_read(opaque, addr, 1);
+}
+
+static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
+{
+ pflash_t *pfl = opaque;
+
+ return pflash_read(pfl, addr, 2);
+}
+
+static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
+{
+ pflash_t *pfl = opaque;
+
+ return pflash_read(pfl, addr, 4);
+}
+
+static void pflash_writeb (void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ pflash_write(opaque, addr, value, 1);
+}
+
+static void pflash_writew (void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ pflash_t *pfl = opaque;
+
+ pflash_write(pfl, addr, value, 2);
+}
+
+static void pflash_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ pflash_t *pfl = opaque;
+
+ pflash_write(pfl, addr, value, 4);
+}
+
+static CPUWriteMemoryFunc *pflash_write_ops[] = {
+ &pflash_writeb,
+ &pflash_writew,
+ &pflash_writel,
+};
+
+static CPUReadMemoryFunc *pflash_read_ops[] = {
+ &pflash_readb,
+ &pflash_readw,
+ &pflash_readl,
+};
+
+/* Count trailing zeroes of a 32 bits quantity */
+static int ctz32 (uint32_t n)
+{
+ int ret;
+
+ ret = 0;
+ if (!(n & 0xFFFF)) {
+ ret += 16;
+ n = n >> 16;
+ }
+ if (!(n & 0xFF)) {
+ ret += 8;
+ n = n >> 8;
+ }
+ if (!(n & 0xF)) {
+ ret += 4;
+ n = n >> 4;
+ }
+ if (!(n & 0x3)) {
+ ret += 2;
+ n = n >> 2;
+ }
+ if (!(n & 0x1)) {
+ ret++;
+ n = n >> 1;
+ }
+#if 0 /* This is not necessary as n is never 0 */
+ if (!n)
+ ret++;
+#endif
+
+ return ret;
+}
+
+pflash_t *pflash_register (target_ulong base, ram_addr_t off,
+ BlockDriverState *bs,
+ target_ulong sector_len, int nb_blocs, int width,
+ uint16_t id0, uint16_t id1,
+ uint16_t id2, uint16_t id3)
+{
+ pflash_t *pfl;
+ target_long total_len;
+
+ total_len = sector_len * nb_blocs;
+ /* XXX: to be fixed */
+ if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
+ total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
+ return NULL;
+ pfl = qemu_mallocz(sizeof(pflash_t));
+ if (pfl == NULL)
+ return NULL;
+ pfl->storage = phys_ram_base + off;
+ pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl);
+ pfl->off = off;
+ cpu_register_physical_memory(base, total_len,
+ off | pfl->fl_mem | IO_MEM_ROMD);
+ pfl->bs = bs;
+ if (pfl->bs) {
+ /* read the initial flash content */
+ bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
+ }
+#if 0 /* XXX: there should be a bit to set up read-only,
+ * the same way the hardware does (with WP pin).
+ */
+ pfl->ro = 1;
+#else
+ pfl->ro = 0;
+#endif
+ pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
+ pfl->base = base;
+ pfl->sector_len = sector_len;
+ pfl->total_len = total_len;
+ pfl->width = width;
+ pfl->wcycle = 0;
+ pfl->cmd = 0;
+ pfl->status = 0;
+ pfl->ident[0] = id0;
+ pfl->ident[1] = id1;
+ pfl->ident[2] = id2;
+ pfl->ident[3] = id3;
+ /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
+ pfl->cfi_len = 0x52;
+ /* Standard "QRY" string */
+ pfl->cfi_table[0x10] = 'Q';
+ pfl->cfi_table[0x11] = 'R';
+ pfl->cfi_table[0x12] = 'Y';
+ /* Command set (AMD/Fujitsu) */
+ pfl->cfi_table[0x13] = 0x02;
+ pfl->cfi_table[0x14] = 0x00;
+ /* Primary extended table address (none) */
+ pfl->cfi_table[0x15] = 0x00;
+ pfl->cfi_table[0x16] = 0x00;
+ /* Alternate command set (none) */
+ pfl->cfi_table[0x17] = 0x00;
+ pfl->cfi_table[0x18] = 0x00;
+ /* Alternate extended table (none) */
+ pfl->cfi_table[0x19] = 0x00;
+ pfl->cfi_table[0x1A] = 0x00;
+ /* Vcc min */
+ pfl->cfi_table[0x1B] = 0x27;
+ /* Vcc max */
+ pfl->cfi_table[0x1C] = 0x36;
+ /* Vpp min (no Vpp pin) */
+ pfl->cfi_table[0x1D] = 0x00;
+ /* Vpp max (no Vpp pin) */
+ pfl->cfi_table[0x1E] = 0x00;
+ /* Reserved */
+ pfl->cfi_table[0x1F] = 0x07;
+ /* Timeout for min size buffer write (16 µs) */
+ pfl->cfi_table[0x20] = 0x04;
+ /* Typical timeout for block erase (512 ms) */
+ pfl->cfi_table[0x21] = 0x09;
+ /* Typical timeout for full chip erase (4096 ms) */
+ pfl->cfi_table[0x22] = 0x0C;
+ /* Reserved */
+ pfl->cfi_table[0x23] = 0x01;
+ /* Max timeout for buffer write */
+ pfl->cfi_table[0x24] = 0x04;
+ /* Max timeout for block erase */
+ pfl->cfi_table[0x25] = 0x0A;
+ /* Max timeout for chip erase */
+ pfl->cfi_table[0x26] = 0x0D;
+ /* Device size */
+ pfl->cfi_table[0x27] = ctz32(total_len) + 1;
+ /* Flash device interface (8 & 16 bits) */
+ pfl->cfi_table[0x28] = 0x02;
+ pfl->cfi_table[0x29] = 0x00;
+ /* Max number of bytes in multi-bytes write */
+ pfl->cfi_table[0x2A] = 0x05;
+ pfl->cfi_table[0x2B] = 0x00;
+ /* Number of erase block regions (uniform) */
+ pfl->cfi_table[0x2C] = 0x01;
+ /* Erase block region 1 */
+ pfl->cfi_table[0x2D] = nb_blocs - 1;
+ pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
+ pfl->cfi_table[0x2F] = sector_len >> 8;
+ pfl->cfi_table[0x30] = sector_len >> 16;
+
+ return pfl;
+}
}
/* PIIX4 acpi pci configuration space, func 3 */
-void pci_piix4_acpi_init(PCIBus *bus)
+void pci_piix4_acpi_init(PCIBus *bus, int devfn)
{
PCIAcpiState *d;
uint8_t *pci_conf;
/* register a function 3 of PIIX4 */
d = (PCIAcpiState *)pci_register_device(
bus, "PIIX4 ACPI", sizeof(PCIAcpiState),
- ((PCIDevice *)piix3_state)->devfn + 3, NULL, NULL);
+ devfn, NULL, NULL);
acpi_state = d;
pci_conf = d->dev.config;
--- /dev/null
+/*
+ * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState I440FXState;
+
+static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+ I440FXState *s = opaque;
+ s->config_reg = val;
+}
+
+static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
+{
+ I440FXState *s = opaque;
+ return s->config_reg;
+}
+
+static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level);
+
+PCIBus *i440fx_init(void)
+{
+ PCIBus *b;
+ PCIDevice *d;
+ I440FXState *s;
+
+ s = qemu_mallocz(sizeof(I440FXState));
+ b = pci_register_bus(piix3_set_irq, NULL, 0);
+ s->bus = b;
+
+ register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
+ register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
+
+ register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
+ register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
+ register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
+ register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
+ register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
+ register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+
+ d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
+ NULL, NULL);
+
+ d->config[0x00] = 0x86; // vendor_id
+ d->config[0x01] = 0x80;
+ d->config[0x02] = 0x37; // device_id
+ d->config[0x03] = 0x12;
+ d->config[0x08] = 0x02; // revision
+ d->config[0x0a] = 0x00; // class_sub = host2pci
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x00; // header_type
+ return b;
+}
+
+/* PIIX3 PCI to ISA bridge */
+
+static PCIDevice *piix3_dev;
+
+/* just used for simpler irq handling. */
+#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
+
+static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
+
+/* return the global irq number corresponding to a given device irq
+ pin. We could also use the bus number to have a more precise
+ mapping. */
+static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+ int slot_addend;
+ slot_addend = (pci_dev->devfn >> 3) - 1;
+ return (irq_num + slot_addend) & 3;
+}
+
+static inline int get_pci_irq_level(int irq_num)
+{
+ int pic_level;
+#if (PCI_IRQ_WORDS == 2)
+ pic_level = ((pci_irq_levels[irq_num][0] |
+ pci_irq_levels[irq_num][1]) != 0);
+#else
+ {
+ int i;
+ pic_level = 0;
+ for(i = 0; i < PCI_IRQ_WORDS; i++) {
+ if (pci_irq_levels[irq_num][i]) {
+ pic_level = 1;
+ break;
+ }
+ }
+ }
+#endif
+ return pic_level;
+}
+
+static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level)
+{
+ int irq_index, shift, pic_irq, pic_level;
+ uint32_t *p;
+
+ irq_num = pci_slot_get_pirq(pci_dev, irq_num);
+ irq_index = pci_dev->irq_index;
+ p = &pci_irq_levels[irq_num][irq_index >> 5];
+ shift = (irq_index & 0x1f);
+ *p = (*p & ~(1 << shift)) | (level << shift);
+
+ /* now we change the pic irq level according to the piix irq mappings */
+ /* XXX: optimize */
+ pic_irq = piix3_dev->config[0x60 + irq_num];
+ if (pic_irq < 16) {
+ /* the pic level is the logical OR of all the PCI irqs mapped
+ to it */
+ pic_level = 0;
+ if (pic_irq == piix3_dev->config[0x60])
+ pic_level |= get_pci_irq_level(0);
+ if (pic_irq == piix3_dev->config[0x61])
+ pic_level |= get_pci_irq_level(1);
+ if (pic_irq == piix3_dev->config[0x62])
+ pic_level |= get_pci_irq_level(2);
+ if (pic_irq == piix3_dev->config[0x63])
+ pic_level |= get_pci_irq_level(3);
+ pic_set_irq(pic_irq, pic_level);
+ }
+}
+
+static void piix3_reset(PCIDevice *d)
+{
+ uint8_t *pci_conf = d->config;
+
+ pci_conf[0x04] = 0x07; // master, memory and I/O
+ pci_conf[0x05] = 0x00;
+ pci_conf[0x06] = 0x00;
+ pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+ pci_conf[0x4c] = 0x4d;
+ pci_conf[0x4e] = 0x03;
+ pci_conf[0x4f] = 0x00;
+ pci_conf[0x60] = 0x80;
+ pci_conf[0x69] = 0x02;
+ pci_conf[0x70] = 0x80;
+ pci_conf[0x76] = 0x0c;
+ pci_conf[0x77] = 0x0c;
+ pci_conf[0x78] = 0x02;
+ pci_conf[0x79] = 0x00;
+ pci_conf[0x80] = 0x00;
+ pci_conf[0x82] = 0x00;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa2] = 0x00;
+ pci_conf[0xa3] = 0x00;
+ pci_conf[0xa4] = 0x00;
+ pci_conf[0xa5] = 0x00;
+ pci_conf[0xa6] = 0x00;
+ pci_conf[0xa7] = 0x00;
+ pci_conf[0xa8] = 0x0f;
+ pci_conf[0xaa] = 0x00;
+ pci_conf[0xab] = 0x00;
+ pci_conf[0xac] = 0x00;
+ pci_conf[0xae] = 0x00;
+}
+
+int piix3_init(PCIBus *bus)
+{
+ PCIDevice *d;
+ uint8_t *pci_conf;
+
+ d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
+ -1, NULL, NULL);
+ register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
+
+ piix3_dev = d;
+ pci_conf = d->config;
+
+ pci_conf[0x00] = 0x86; // Intel
+ pci_conf[0x01] = 0x80;
+ pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ pci_conf[0x03] = 0x70;
+ pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+ pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+ piix3_reset(d);
+ return d->devfn;
+}
+
+/***********************************************************/
+/* XXX: the following should be moved to the PC BIOS */
+
+static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
+{
+ return cpu_inb(NULL, addr);
+}
+
+static void isa_outb(uint32_t val, uint32_t addr)
+{
+ cpu_outb(NULL, addr, val);
+}
+
+static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
+{
+ return cpu_inw(NULL, addr);
+}
+
+static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
+{
+ cpu_outw(NULL, addr, val);
+}
+
+static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
+{
+ return cpu_inl(NULL, addr);
+}
+
+static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
+{
+ cpu_outl(NULL, addr, val);
+}
+
+static uint32_t pci_bios_io_addr;
+static uint32_t pci_bios_mem_addr;
+/* host irqs corresponding to PCI irqs A-D */
+static uint8_t pci_irqs[4] = { 10, 11, 10, 11 };
+
+static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ pci_data_write(s, addr, val, 4);
+}
+
+static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ pci_data_write(s, addr, val, 2);
+}
+
+static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ pci_data_write(s, addr, val, 1);
+}
+
+static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ return pci_data_read(s, addr, 4);
+}
+
+static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ return pci_data_read(s, addr, 2);
+}
+
+static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ return pci_data_read(s, addr, 1);
+}
+
+static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
+{
+ PCIIORegion *r;
+ uint16_t cmd;
+ uint32_t ofs;
+
+ if ( region_num == PCI_ROM_SLOT ) {
+ ofs = 0x30;
+ }else{
+ ofs = 0x10 + region_num * 4;
+ }
+
+ pci_config_writel(d, ofs, addr);
+ r = &d->io_regions[region_num];
+
+ /* enable memory mappings */
+ cmd = pci_config_readw(d, PCI_COMMAND);
+ if ( region_num == PCI_ROM_SLOT )
+ cmd |= 2;
+ else if (r->type & PCI_ADDRESS_SPACE_IO)
+ cmd |= 1;
+ else
+ cmd |= 2;
+ pci_config_writew(d, PCI_COMMAND, cmd);
+}
+
+static void pci_bios_init_device(PCIDevice *d)
+{
+ int class;
+ PCIIORegion *r;
+ uint32_t *paddr;
+ int i, pin, pic_irq, vendor_id, device_id;
+
+ class = pci_config_readw(d, PCI_CLASS_DEVICE);
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+ switch(class) {
+ case 0x0101:
+ if (vendor_id == 0x8086 && device_id == 0x7010) {
+ /* PIIX3 IDE */
+ pci_config_writew(d, 0x40, 0x8000); // enable IDE0
+ pci_config_writew(d, 0x42, 0x8000); // enable IDE1
+ goto default_map;
+ } else {
+ /* IDE: we map it as in ISA mode */
+ pci_set_io_region_addr(d, 0, 0x1f0);
+ pci_set_io_region_addr(d, 1, 0x3f4);
+ pci_set_io_region_addr(d, 2, 0x170);
+ pci_set_io_region_addr(d, 3, 0x374);
+ }
+ break;
+ case 0x0680:
+ if (vendor_id == 0x8086 && device_id == 0x7113) {
+ /* PIIX4 ACPI PM */
+ pci_config_writew(d, 0x20, 0x0000); /* NO smb bus IO enable in PIIX4 */
+ pci_config_writew(d, 0x22, 0x0000);
+ goto default_map;
+ }
+ break;
+ case 0x0300:
+ if (vendor_id != 0x1234)
+ goto default_map;
+ /* VGA: map frame buffer to default Bochs VBE address */
+ pci_set_io_region_addr(d, 0, 0xE0000000);
+ break;
+ case 0x0800:
+ /* PIC */
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+ if (vendor_id == 0x1014) {
+ /* IBM */
+ if (device_id == 0x0046 || device_id == 0xFFFF) {
+ /* MPIC & MPIC2 */
+ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
+ }
+ }
+ break;
+ case 0xff00:
+ if (vendor_id == 0x0106b &&
+ (device_id == 0x0017 || device_id == 0x0022)) {
+ /* macio bridge */
+ pci_set_io_region_addr(d, 0, 0x80800000);
+ }
+ break;
+ default:
+ default_map:
+ /* default memory mappings */
+ for(i = 0; i < PCI_NUM_REGIONS; i++) {
+ r = &d->io_regions[i];
+ if (r->size) {
+ if (r->type & PCI_ADDRESS_SPACE_IO)
+ paddr = &pci_bios_io_addr;
+ else
+ paddr = &pci_bios_mem_addr;
+ *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
+ pci_set_io_region_addr(d, i, *paddr);
+ *paddr += r->size;
+ }
+ }
+ break;
+ }
+
+ /* map the interrupt */
+ pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
+ if (pin != 0) {
+ pin = pci_slot_get_pirq(d, pin - 1);
+ pic_irq = pci_irqs[pin];
+ pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
+ }
+
+ if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) {
+ // PIIX4 ACPI PM
+ pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4
+ pci_config_writew(d, 0x22, 0x0000);
+ pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9
+ pci_config_writew(d, 0x3d, 0x0001);
+ }
+}
+
+/*
+ * This function initializes the PCI devices as a normal PCI BIOS
+ * would do. It is provided just in case the BIOS has no support for
+ * PCI.
+ */
+void pci_bios_init(void)
+{
+ int i, irq;
+ uint8_t elcr[2];
+
+ pci_bios_io_addr = 0xc000;
+ pci_bios_mem_addr = 0xf0000000;
+
+ /* activate IRQ mappings */
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+ for(i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+ /* activate irq remapping in PIIX */
+ pci_config_writeb(piix3_dev, 0x60 + i, irq);
+ }
+ isa_outb(elcr[0], 0x4d0);
+ isa_outb(elcr[1], 0x4d1);
+
+ pci_for_each_device(pci_bios_init_device);
+}
+
/*
- * Arm PrimeCell PL050 Kyeboard / Mouse Interface
+ * Arm PrimeCell PL050 Keyboard / Mouse Interface
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
if (is_heathrow) {
isa_mem_base = 0x80000000;
- pci_bus = pci_grackle_init(0xfec00000);
/* Register 2 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
/* init basic PC hardware */
+ pic = heathrow_pic_init(&heathrow_pic_mem_index);
+ set_irq = heathrow_pic_set_irq;
+ pci_bus = pci_grackle_init(0xfec00000, pic);
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
- pic = heathrow_pic_init(&heathrow_pic_mem_index);
- set_irq = heathrow_pic_set_irq;
- pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
- pci_bus = pci_pmac_init();
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
+ pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
+ set_irq = openpic_set_irq;
+ pci_bus = pci_pmac_init(pic);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
- pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
- set_irq = openpic_set_irq;
- pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
arch_name = "MAC99";
}
-
+
+ if (usb_enabled) {
+ usb_ohci_init(pci_bus, 3, -1);
+ }
+
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
#endif
+ if (usb_enabled) {
+ usb_ohci_init(pci_bus, 3, -1);
+ }
+
nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
if (nvram == NULL)
return;
--- /dev/null
+/*
+ * QEMU PREP PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState PREPPCIState;
+
+static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+ s->config_reg = val;
+}
+
+static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr)
+{
+ PREPPCIState *s = opaque;
+ return s->config_reg;
+}
+
+static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
+{
+ int i;
+
+ for(i = 0; i < 11; i++) {
+ if ((addr & (1 << (11 + i))) != 0)
+ break;
+ }
+ return (addr & 0x7ff) | (i << 11);
+}
+
+static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+ pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
+}
+
+static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
+}
+
+static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
+}
+
+static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
+{
+ PREPPCIState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
+ return val;
+}
+
+static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
+{
+ PREPPCIState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
+{
+ PREPPCIState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static CPUWriteMemoryFunc *PPC_PCIIO_write[] = {
+ &PPC_PCIIO_writeb,
+ &PPC_PCIIO_writew,
+ &PPC_PCIIO_writel,
+};
+
+static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
+ &PPC_PCIIO_readb,
+ &PPC_PCIIO_readw,
+ &PPC_PCIIO_readl,
+};
+
+static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ /* XXX: we do not simulate the hardware - we rely on the BIOS to
+ set correctly for irq line field */
+ pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_prep_init(void)
+{
+ PREPPCIState *s;
+ PCIDevice *d;
+ int PPC_io_memory;
+
+ s = qemu_mallocz(sizeof(PREPPCIState));
+ s->bus = pci_register_bus(prep_set_irq, NULL, 0);
+
+ register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
+ register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
+
+ register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
+ register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
+ register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
+ register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
+ register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
+ register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+
+ PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
+ PPC_PCIIO_write, s);
+ cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
+
+ /* PCI host bridge */
+ d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
+ sizeof(PCIDevice), 0, NULL, NULL);
+ d->config[0x00] = 0x57; // vendor_id : Motorola
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x01; // device_id : Raven
+ d->config[0x03] = 0x48;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ d->config[0x34] = 0x00; // capabilities_pointer
+
+ return s->bus;
+}
+
* Modifications:
* 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver)
- *
+ *
+ * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver
+ * HW revision ID changes for FreeBSD driver
+ *
+ * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver
+ * Corrected packet transfer reassembly routine for 8139C+ mode
+ * Rearranged debugging print statements
+ * Implemented PCI timer interrupt (disabled by default)
+ * Implemented Tally Counters, increased VM load/save version
+ * Implemented IP/TCP/UDP checksum task offloading
+ *
+ * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading
+ * Fixed MTU=1500 for produced ethernet frames
+ *
+ * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing
+ * segmentation offloading
+ * Removed slirp.h dependency
+ * Added rx/tx buffer reset when enabling rx/tx operation
*/
#include "vl.h"
-
/* debug RTL8139 card */
//#define DEBUG_RTL8139 1
+#define PCI_FREQUENCY 33000000L
+
/* debug RTL8139 card C+ mode only */
//#define DEBUG_RTL8139CP 1
ignored by most drivers, disabled by default */
//#define RTL8139_CALCULATE_RXCRC 1
+/* Uncomment to enable on-board timer interrupts */
+//#define RTL8139_ONBOARD_TIMER 1
#if defined(RTL8139_CALCULATE_RXCRC)
/* For crc32 */
#define MOD2(input, size) \
( ( input ) & ( size - 1 ) )
+#if defined (DEBUG_RTL8139)
+# define DEBUG_PRINT(x) do { printf x ; } while (0)
+#else
+# define DEBUG_PRINT(x)
+#endif
+
/* Symbolic offsets to registers. */
enum RTL8139_registers {
MAC0 = 0, /* Ethernet hardware address. */
MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
+ TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
+ /* Dump Tally Conter control register(64bit). C+ mode only */
+ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
RxBuf = 0x30,
ChipCmd = 0x37,
RxBufPtr = 0x38,
/* C+ mode */
enum CplusCmdBits {
- CPlusRxEnb = 0x0002,
- CPlusTxEnb = 0x0001,
+ CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */
+ CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
+ CPlusRxEnb = 0x0002,
+ CPlusTxEnb = 0x0001,
};
/* Interrupt register bits, using my own meaningful names. */
(b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
+#define RTL8139_PCI_REVID_8139 0x10
+#define RTL8139_PCI_REVID_8139CPLUS 0x20
+
+#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS
+
/* Size is 64 * 16bit words */
#define EEPROM_9346_ADDR_BITS 6
#define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS)
uint8_t eedo;
} EEprom9346;
+typedef struct RTL8139TallyCounters
+{
+ /* Tally counters */
+ uint64_t TxOk;
+ uint64_t RxOk;
+ uint64_t TxERR;
+ uint32_t RxERR;
+ uint16_t MissPkt;
+ uint16_t FAE;
+ uint32_t Tx1Col;
+ uint32_t TxMCol;
+ uint64_t RxOkPhy;
+ uint64_t RxOkBrd;
+ uint32_t RxOkMul;
+ uint16_t TxAbt;
+ uint16_t TxUndrn;
+} RTL8139TallyCounters;
+
+/* Clears all tally counters */
+static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
+
+/* Writes tally counters to specified physical memory address */
+static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters);
+
+/* Loads values of tally counters from VM state file */
+static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters);
+
+/* Saves values of tally counters to VM state file */
+static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters);
+
typedef struct RTL8139State {
uint8_t phys[8]; /* mac address */
uint8_t mult[8]; /* multicast mask array */
- uint32_t TxStatus[4]; /* TxStatus0 */
+ uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
uint32_t TxAddr[4]; /* TxAddr0 */
uint32_t RxBuf; /* Receive buffer */
uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
uint32_t RxRingAddrHI;
EEprom9346 eeprom;
-
+
+ uint32_t TCTR;
+ uint32_t TimerInt;
+ int64_t TCTR_base;
+
+ /* Tally counters */
+ RTL8139TallyCounters tally_counters;
+
+ /* Non-persistent data */
+ uint8_t *cplus_txbuffer;
+ int cplus_txbuffer_len;
+ int cplus_txbuffer_offset;
+
+ /* PCI interrupt timer */
+ QEMUTimer *timer;
+
} RTL8139State;
void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom command 0x%02x\n", command);
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
switch (command & Chip9346_op_mask)
{
eeprom->eedo = 0;
eeprom->tick = 0;
eeprom->mode = Chip9346_data_read;
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->output);
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n",
+ eeprom->address, eeprom->output));
}
break;
eeprom->input = 0;
eeprom->tick = 0;
eeprom->mode = Chip9346_none; /* Chip9346_data_write */
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom begin write to address 0x%02x\n",
- eeprom->address);
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n",
+ eeprom->address));
}
break;
default:
switch (command & Chip9346_op_ext_mask)
{
case Chip9346_op_write_enable:
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom write enabled\n");
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom write enabled\n"));
break;
case Chip9346_op_write_all:
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom begin write all\n");
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom begin write all\n"));
break;
case Chip9346_op_write_disable:
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom write disabled\n");
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom write disabled\n"));
break;
}
break;
++ eeprom->tick;
-#if defined(DEBUG_RTL8139)
- printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo);
-#endif
+ DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo));
switch (eeprom->mode)
{
eeprom->mode = Chip9346_read_command;
eeprom->tick = 0;
eeprom->input = 0;
-#if defined(DEBUG_RTL8139)
- printf("eeprom: +++ synchronized, begin command read\n");
-#endif
+ DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n"));
}
break;
eeprom->output <<= 1;
if (eeprom->tick == 16)
{
+#if 1
+ // the FreeBSD drivers (rl and re) don't explicitly toggle
+ // CS between reads (or does setting Cfg9346 to 0 count too?),
+ // so we need to enter wait-for-command state here
+ eeprom->mode = Chip9346_enter_command_mode;
+ eeprom->input = 0;
+ eeprom->tick = 0;
+
+ DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n"));
+#else
+ // original behaviour
++eeprom->address;
eeprom->address &= EEPROM_9346_ADDR_MASK;
eeprom->output = eeprom->contents[eeprom->address];
eeprom->tick = 0;
-#if defined(DEBUG_RTL8139)
- printf("eeprom: +++ read next address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->output);
+ DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n",
+ eeprom->address, eeprom->output));
#endif
}
break;
eeprom->input = (eeprom->input << 1) | (bit & 1);
if (eeprom->tick == 16)
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->input);
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
+ eeprom->address, eeprom->input));
+
eeprom->contents[eeprom->address] = eeprom->input;
eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
eeprom->tick = 0;
{
eeprom->contents[i] = eeprom->input;
}
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: eeprom filled with data=0x%04x\n",
- eeprom->input);
-#endif
+ DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n",
+ eeprom->input));
+
eeprom->mode = Chip9346_enter_command_mode;
eeprom->tick = 0;
eeprom->input = 0;
eeprom->eesk = eesk;
eeprom->eedi = eedi;
-#if defined(DEBUG_RTL8139)
- printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo);
-#endif
+ DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
+ eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo));
if (!old_eecs && eecs)
{
eeprom->output = 0;
eeprom->mode = Chip9346_enter_command_mode;
-#if defined(DEBUG_RTL8139)
- printf("=== eeprom: begin access, enter command mode\n");
-#endif
-
+ DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n"));
}
if (!eecs)
{
-#if defined(DEBUG_RTL8139)
- printf("=== eeprom: end access\n");
-#endif
+ DEBUG_PRINT(("=== eeprom: end access\n"));
return;
}
{
int isr;
isr = (s->IntrStatus & s->IntrMask) & 0xffff;
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
- s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask);
-#endif
+
+ DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
+ s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask));
+
if (s->irq == 16) {
/* PCI irq */
pci_set_irq(s->pci_dev, 0, (isr != 0));
/* write packet data */
if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s))
{
- #if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped);
- #endif
+ DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped));
if (size > wrapped)
{
}
}
-static void rtl8139_receive(void *opaque, const uint8_t *buf, int size)
+static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt)
{
RTL8139State *s = opaque;
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: received len=%d\n", size);
-#endif
+ DEBUG_PRINT((">>> RTL8139: received len=%d\n", size));
/* test if board clock is stopped */
if (!s->clock_enabled)
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: stopped ==========================\n");
-#endif
+ DEBUG_PRINT(("RTL8139: stopped ==========================\n"));
return;
}
if (!rtl8139_receiver_enabled(s))
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: receiver disabled ================\n");
-#endif
+ DEBUG_PRINT(("RTL8139: receiver disabled ================\n"));
return;
}
/* XXX: check this */
if (s->RxConfig & AcceptAllPhys) {
/* promiscuous: receive all */
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: packet received in promiscuous mode\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n"));
} else {
if (!memcmp(buf, broadcast_macaddr, 6)) {
/* broadcast address */
if (!(s->RxConfig & AcceptBroadcast))
{
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: broadcast packet rejected\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+
return;
}
packet_header |= RxBroadcast;
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: broadcast packet received\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: broadcast packet received\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxOkBrd;
+
} else if (buf[0] & 0x01) {
/* multicast */
if (!(s->RxConfig & AcceptMulticast))
{
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: multicast packet rejected\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+
return;
}
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
{
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: multicast address mismatch\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+
return;
}
packet_header |= RxMulticast;
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: multicast packet received\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: multicast packet received\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxOkMul;
+
} else if (s->phys[0] == buf[0] &&
s->phys[1] == buf[1] &&
s->phys[2] == buf[2] &&
/* match */
if (!(s->RxConfig & AcceptMyPhys))
{
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: rejecting physical address matching packet\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+
return;
}
packet_header |= RxPhysical;
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: physical address matching packet received\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxOkPhy;
} else {
-#if defined(DEBUG_RTL8139)
- printf(">>> RTL8139: unknown packet\n");
-#endif
+ DEBUG_PRINT((">>> RTL8139: unknown packet\n"));
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+
return;
}
}
if (rtl8139_cp_receiver_enabled(s))
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: in C+ Rx mode ================\n");
-#endif
+ DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n"));
/* begin C+ receiver mode */
cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
cplus_rx_ring_desc += 16 * descriptor;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = 0x%8lx\n",
- descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc);
-#endif
+ DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n",
+ descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc));
uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
rxbufHI = le32_to_cpu(val);
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
+ DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
descriptor,
- rxdw0, rxdw1, rxbufLO, rxbufHI);
-#endif
+ rxdw0, rxdw1, rxbufLO, rxbufHI));
if (!(rxdw0 & CP_RX_OWN))
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor));
+
s->IntrStatus |= RxOverflow;
++s->RxMissed;
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+ ++s->tally_counters.MissPkt;
+
rtl8139_update_irq(s);
return;
}
uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
+ /* TODO: scatter the packet over available receive ring descriptors space */
+
if (size+4 > rx_space)
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n",
- descriptor, rx_space, size);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n",
+ descriptor, rx_space, size));
+
s->IntrStatus |= RxOverflow;
++s->RxMissed;
+
+ /* update tally counter */
+ ++s->tally_counters.RxERR;
+ ++s->tally_counters.MissPkt;
+
rtl8139_update_irq(s);
return;
}
/* receive/copy to target memory */
cpu_physical_memory_write( rx_addr, buf, size );
+ if (s->CpCmd & CPlusRxChkSum)
+ {
+ /* do some packet checksumming */
+ }
+
/* write checksum */
#if defined (RTL8139_CALCULATE_RXCRC)
val = cpu_to_le32(crc32(~0, buf, size));
val = cpu_to_le32(rxdw1);
cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
+ /* update tally counter */
+ ++s->tally_counters.RxOk;
+
/* seek to next Rx descriptor */
if (rxdw0 & CP_RX_EOR)
{
++s->currCPlusRxDesc;
}
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: done C+ Rx mode ----------------\n");
-#endif
+ DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n"));
}
else
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: in ring Rx mode ================\n");
-#endif
+ DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n"));
+
/* begin ring receiver mode */
int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
if (avail != 0 && size + 8 >= avail)
{
-#if defined(DEBUG_RTL8139)
- printf("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
-#endif
+ DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
+ s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8));
+
s->IntrStatus |= RxOverflow;
++s->RxMissed;
rtl8139_update_irq(s);
/* now we can signal we have received something */
-#if defined(DEBUG_RTL8139)
- printf(" received: rx buffer length %d head 0x%04x read 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-#endif
-
+ DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n",
+ s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
}
s->IntrStatus |= RxOK;
- rtl8139_update_irq(s);
+
+ if (do_interrupt)
+ {
+ rtl8139_update_irq(s);
+ }
+}
+
+static void rtl8139_receive(void *opaque, const uint8_t *buf, int size)
+{
+ rtl8139_do_receive(opaque, buf, size, 1);
}
static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
/* prepare eeprom */
s->eeprom.contents[0] = 0x8129;
+#if 1
+ // PCI vendor and device ID should be mirrored here
+ s->eeprom.contents[1] = 0x10ec;
+ s->eeprom.contents[2] = 0x8139;
+#endif
memcpy(&s->eeprom.contents[7], s->macaddr, 6);
/* mark all status registers as owned by host */
// s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk
s->clock_enabled = 0;
#else
- s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 0, 0); // RTL-8139C HasLWake
+ s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
s->clock_enabled = 1;
#endif
s->NWayAdvert = 0x05e1; /* all modes, full duplex */
s->NWayLPAR = 0x05e1; /* all modes, full duplex */
s->NWayExpansion = 0x0001; /* autonegotiation supported */
+
+ /* also reset timer and disable timer interrupt */
+ s->TCTR = 0;
+ s->TimerInt = 0;
+ s->TCTR_base = 0;
+
+ /* reset tally counters */
+ RTL8139TallyCounters_clear(&s->tally_counters);
+}
+
+void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
+{
+ counters->TxOk = 0;
+ counters->RxOk = 0;
+ counters->TxERR = 0;
+ counters->RxERR = 0;
+ counters->MissPkt = 0;
+ counters->FAE = 0;
+ counters->Tx1Col = 0;
+ counters->TxMCol = 0;
+ counters->RxOkPhy = 0;
+ counters->RxOkBrd = 0;
+ counters->RxOkMul = 0;
+ counters->TxAbt = 0;
+ counters->TxUndrn = 0;
+}
+
+static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters)
+{
+ uint16_t val16;
+ uint32_t val32;
+ uint64_t val64;
+
+ val64 = cpu_to_le64(tally_counters->TxOk);
+ cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8);
+
+ val64 = cpu_to_le64(tally_counters->RxOk);
+ cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8);
+
+ val64 = cpu_to_le64(tally_counters->TxERR);
+ cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8);
+
+ val32 = cpu_to_le32(tally_counters->RxERR);
+ cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4);
+
+ val16 = cpu_to_le16(tally_counters->MissPkt);
+ cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2);
+
+ val16 = cpu_to_le16(tally_counters->FAE);
+ cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2);
+
+ val32 = cpu_to_le32(tally_counters->Tx1Col);
+ cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4);
+
+ val32 = cpu_to_le32(tally_counters->TxMCol);
+ cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4);
+
+ val64 = cpu_to_le64(tally_counters->RxOkPhy);
+ cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8);
+
+ val64 = cpu_to_le64(tally_counters->RxOkBrd);
+ cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8);
+
+ val32 = cpu_to_le32(tally_counters->RxOkMul);
+ cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4);
+
+ val16 = cpu_to_le16(tally_counters->TxAbt);
+ cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2);
+
+ val16 = cpu_to_le16(tally_counters->TxUndrn);
+ cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2);
+}
+
+/* Loads values of tally counters from VM state file */
+static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters)
+{
+ qemu_get_be64s(f, &tally_counters->TxOk);
+ qemu_get_be64s(f, &tally_counters->RxOk);
+ qemu_get_be64s(f, &tally_counters->TxERR);
+ qemu_get_be32s(f, &tally_counters->RxERR);
+ qemu_get_be16s(f, &tally_counters->MissPkt);
+ qemu_get_be16s(f, &tally_counters->FAE);
+ qemu_get_be32s(f, &tally_counters->Tx1Col);
+ qemu_get_be32s(f, &tally_counters->TxMCol);
+ qemu_get_be64s(f, &tally_counters->RxOkPhy);
+ qemu_get_be64s(f, &tally_counters->RxOkBrd);
+ qemu_get_be32s(f, &tally_counters->RxOkMul);
+ qemu_get_be16s(f, &tally_counters->TxAbt);
+ qemu_get_be16s(f, &tally_counters->TxUndrn);
+}
+
+/* Saves values of tally counters to VM state file */
+static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters)
+{
+ qemu_put_be64s(f, &tally_counters->TxOk);
+ qemu_put_be64s(f, &tally_counters->RxOk);
+ qemu_put_be64s(f, &tally_counters->TxERR);
+ qemu_put_be32s(f, &tally_counters->RxERR);
+ qemu_put_be16s(f, &tally_counters->MissPkt);
+ qemu_put_be16s(f, &tally_counters->FAE);
+ qemu_put_be32s(f, &tally_counters->Tx1Col);
+ qemu_put_be32s(f, &tally_counters->TxMCol);
+ qemu_put_be64s(f, &tally_counters->RxOkPhy);
+ qemu_put_be64s(f, &tally_counters->RxOkBrd);
+ qemu_put_be32s(f, &tally_counters->RxOkMul);
+ qemu_put_be16s(f, &tally_counters->TxAbt);
+ qemu_put_be16s(f, &tally_counters->TxUndrn);
}
static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ChipCmd write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val));
if (val & CmdReset)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ChipCmd reset\n");
-#endif
+ DEBUG_PRINT(("RTL8139: ChipCmd reset\n"));
rtl8139_reset(s);
}
if (val & CmdRxEnb)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ChipCmd enable receiver\n");
-#endif
+ DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n"));
+
+ s->currCPlusRxDesc = 0;
}
if (val & CmdTxEnb)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ChipCmd enable transmitter\n");
-#endif
+ DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n"));
+
+ s->currCPlusTxDesc = 0;
}
/* mask unwriteable bits */
if (unread != 0)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: receiver buffer data available 0x%04x\n", unread);
-#endif
+ DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread));
return 0;
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: receiver buffer is empty\n");
-#endif
+ DEBUG_PRINT(("RTL8139: receiver buffer is empty\n"));
return 1;
}
if (rtl8139_RxBufferEmpty(s))
ret |= RxBufEmpty;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ChipCmd read val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret));
return ret;
}
{
val &= 0xffff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ command register write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0xff84, s->CpCmd);
{
uint32_t ret = s->CpCmd;
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ command register read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret));
+
+ return ret;
+}
+
+static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
+{
+ DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val));
+}
+
+static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
+{
+ uint32_t ret = 0;
+
+ DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret));
return ret;
}
return 1;
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Configuration registers are write-protected\n");
-#endif
+ DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n"));
return 0;
}
{
val &= 0xffff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val));
/* mask unwriteable bits */
uint32 mask = 0x4cff;
{
uint32_t ret = s->BasicModeCtrl;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret));
return ret;
}
{
val &= 0xffff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
{
uint32_t ret = s->BasicModeStatus;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret));
return ret;
}
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Cfg9346 write val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0x31, s->Cfg9346);
}
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Cfg9346 read val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret));
return ret;
}
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config0 write val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val));
if (!rtl8139_config_writeable(s))
return;
{
uint32_t ret = s->Config0;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config0 read val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret));
return ret;
}
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config1 write val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val));
if (!rtl8139_config_writeable(s))
return;
{
uint32_t ret = s->Config1;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config1 read val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret));
return ret;
}
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config3 write val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val));
if (!rtl8139_config_writeable(s))
return;
{
uint32_t ret = s->Config3;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config3 read val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret));
return ret;
}
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config4 write val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val));
if (!rtl8139_config_writeable(s))
return;
{
uint32_t ret = s->Config4;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config4 read val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret));
return ret;
}
{
val &= 0xff;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config5 write val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0x80, s->Config5);
{
uint32_t ret = s->Config5;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: Config5 read val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret));
return ret;
}
{
if (!rtl8139_transmitter_enabled(s))
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val));
return;
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TxConfig write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val));
val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
-#endif
- uint32_t tc = s->TxConfig;
- tc &= 0xFFFFFF00;
- tc |= (val & 0x000000FF);
- rtl8139_TxConfig_write(s, tc);
+ DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val));
+
+ uint32_t tc = s->TxConfig;
+ tc &= 0xFFFFFF00;
+ tc |= (val & 0x000000FF);
+ rtl8139_TxConfig_write(s, tc);
}
static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
{
uint32_t ret = s->TxConfig;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TxConfig read val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret));
return ret;
}
static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxConfig write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
/* reset buffer size and read/write pointers */
rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize);
-#endif
+ DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize));
}
static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
{
uint32_t ret = s->RxConfig;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxConfig read val=0x%08x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret));
return ret;
}
+static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt)
+{
+ if (!size)
+ {
+ DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n"));
+ return;
+ }
+
+ if (TxLoopBack == (s->TxConfig & TxLoopBack))
+ {
+ DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n"));
+ rtl8139_do_receive(s, buf, size, do_interrupt);
+ }
+ else
+ {
+ qemu_send_packet(s->vc, buf, size);
+ }
+}
+
static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
{
if (!rtl8139_transmitter_enabled(s))
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", descriptor);
-#endif
+ DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n",
+ descriptor));
return 0;
}
if (s->TxStatus[descriptor] & TxHostOwns)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", descriptor, s->TxStatus[descriptor]);
-#endif
+ DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n",
+ descriptor, s->TxStatus[descriptor]));
return 0;
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ transmitting from descriptor %d\n", descriptor);
-#endif
+ DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor));
int txsize = s->TxStatus[descriptor] & 0x1fff;
uint8_t txbuffer[0x2000];
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]);
-#endif
- cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
+ DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n",
+ txsize, s->TxAddr[descriptor]));
- qemu_send_packet(s->vc, txbuffer, txsize);
+ cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
/* Mark descriptor as transferred */
s->TxStatus[descriptor] |= TxHostOwns;
s->TxStatus[descriptor] |= TxStatOK;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor);
-#endif
+ rtl8139_transfer_frame(s, txbuffer, txsize, 0);
+
+ DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor));
/* update interrupt */
s->IntrStatus |= TxOK;
return 1;
}
+/* structures and macros for task offloading */
+typedef struct ip_header
+{
+ uint8_t ip_ver_len; /* version and header length */
+ uint8_t ip_tos; /* type of service */
+ uint16_t ip_len; /* total length */
+ uint16_t ip_id; /* identification */
+ uint16_t ip_off; /* fragment offset field */
+ uint8_t ip_ttl; /* time to live */
+ uint8_t ip_p; /* protocol */
+ uint16_t ip_sum; /* checksum */
+ uint32_t ip_src,ip_dst; /* source and dest address */
+} ip_header;
+
+#define IP_HEADER_VERSION_4 4
+#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
+#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
+
+typedef struct tcp_header
+{
+ uint16_t th_sport; /* source port */
+ uint16_t th_dport; /* destination port */
+ uint32_t th_seq; /* sequence number */
+ uint32_t th_ack; /* acknowledgement number */
+ uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
+ uint16_t th_win; /* window */
+ uint16_t th_sum; /* checksum */
+ uint16_t th_urp; /* urgent pointer */
+} tcp_header;
+
+typedef struct udp_header
+{
+ uint16_t uh_sport; /* source port */
+ uint16_t uh_dport; /* destination port */
+ uint16_t uh_ulen; /* udp length */
+ uint16_t uh_sum; /* udp checksum */
+} udp_header;
+
+typedef struct ip_pseudo_header
+{
+ uint32_t ip_src;
+ uint32_t ip_dst;
+ uint8_t zeros;
+ uint8_t ip_proto;
+ uint16_t ip_payload;
+} ip_pseudo_header;
+
+#define IP_PROTO_TCP 6
+#define IP_PROTO_UDP 17
+
+#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
+#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
+#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
+
+#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
+
+#define TCP_FLAG_FIN 0x01
+#define TCP_FLAG_PUSH 0x08
+
+/* produces ones' complement sum of data */
+static uint16_t ones_complement_sum(uint8_t *data, size_t len)
+{
+ uint32_t result = 0;
+
+ for (; len > 1; data+=2, len-=2)
+ {
+ result += *(uint16_t*)data;
+ }
+
+ /* add the remainder byte */
+ if (len)
+ {
+ uint8_t odd[2] = {*data, 0};
+ result += *(uint16_t*)odd;
+ }
+
+ while (result>>16)
+ result = (result & 0xffff) + (result >> 16);
+
+ return result;
+}
+
+static uint16_t ip_checksum(void *data, size_t len)
+{
+ return ~ones_complement_sum((uint8_t*)data, len);
+}
+
static int rtl8139_cplus_transmit_one(RTL8139State *s)
{
if (!rtl8139_transmitter_enabled(s))
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode: transmitter disabled\n");
-#endif
+ DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n"));
return 0;
}
if (!rtl8139_cp_transmitter_enabled(s))
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode: C+ transmitter disabled\n");
-#endif
+ DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n"));
return 0 ;
}
/* Normal priority ring */
cplus_tx_ring_desc += 16 * descriptor;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n",
- descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc);
-#endif
+ DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n",
+ descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc));
uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
txbufHI = le32_to_cpu(val);
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n",
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n",
descriptor,
- txdw0, txdw1, txbufLO, txbufHI);
-#endif
+ txdw0, txdw1, txbufLO, txbufHI));
/* w0 ownership flag */
#define CP_TX_OWN (1<<31)
#define CP_TX_LS (1<<28)
/* large send packet flag */
#define CP_TX_LGSEN (1<<27)
+/* large send MSS mask, bits 16...25 */
+#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
+
/* IP checksum offload flag */
#define CP_TX_IPCS (1<<18)
/* UDP checksum offload flag */
if (!(txdw0 & CP_TX_OWN))
{
-#if defined(DEBUG_RTL8139)
- printf("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor));
return 0 ;
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
-#endif
+ DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor));
+
+ if (txdw0 & CP_TX_FS)
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor));
+
+ /* reset internal buffer offset */
+ s->cplus_txbuffer_offset = 0;
+ }
int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
- uint8_t txbuffer[CP_TX_BUFFER_SIZE];
+ /* make sure we have enough space to assemble the packet */
+ if (!s->cplus_txbuffer)
+ {
+ s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
+ s->cplus_txbuffer = malloc(s->cplus_txbuffer_len);
+ s->cplus_txbuffer_offset = 0;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at 0x%08x\n", txsize, tx_addr);
-#endif
- cpu_physical_memory_read(tx_addr, txbuffer, txsize);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len));
+ }
+
+ while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+ {
+ s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
+ s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
+
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len));
+ }
+
+ if (!s->cplus_txbuffer)
+ {
+ /* out of memory */
+
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len));
+
+ /* update tally counter */
+ ++s->tally_counters.TxERR;
+ ++s->tally_counters.TxAbt;
+
+ return 0;
+ }
+
+ /* append more data to the packet */
- /* transmit the packet */
- qemu_send_packet(s->vc, txbuffer, txsize);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n",
+ txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset));
+
+ cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
+ s->cplus_txbuffer_offset += txsize;
+
+ /* seek to next Rx descriptor */
+ if (txdw0 & CP_TX_EOR)
+ {
+ s->currCPlusTxDesc = 0;
+ }
+ else
+ {
+ ++s->currCPlusTxDesc;
+ if (s->currCPlusTxDesc >= 64)
+ s->currCPlusTxDesc = 0;
+ }
/* transfer ownership to target */
txdw0 &= ~CP_RX_OWN;
// val = cpu_to_le32(txdw1);
// cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4);
- /* seek to next Rx descriptor */
- if (txdw0 & CP_TX_EOR)
+ /* Now decide if descriptor being processed is holding the last segment of packet */
+ if (txdw0 & CP_TX_LS)
{
- s->currCPlusTxDesc = 0;
+ DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor));
+
+ /* can transfer fully assembled packet */
+
+ uint8_t *saved_buffer = s->cplus_txbuffer;
+ int saved_size = s->cplus_txbuffer_offset;
+ int saved_buffer_len = s->cplus_txbuffer_len;
+
+ /* reset the card space to protect from recursive call */
+ s->cplus_txbuffer = NULL;
+ s->cplus_txbuffer_offset = 0;
+ s->cplus_txbuffer_len = 0;
+
+ if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n"));
+
+ #define ETH_P_IP 0x0800 /* Internet Protocol packet */
+ #define ETH_HLEN 14
+ #define ETH_MTU 1500
+
+ /* ip packet header */
+ ip_header *ip = 0;
+ int hlen = 0;
+ uint8_t ip_protocol = 0;
+ uint16_t ip_data_len = 0;
+
+ uint8_t *eth_payload_data = 0;
+ size_t eth_payload_len = 0;
+
+ int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
+ if (proto == ETH_P_IP)
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n"));
+
+ /* not aligned */
+ eth_payload_data = saved_buffer + ETH_HLEN;
+ eth_payload_len = saved_size - ETH_HLEN;
+
+ ip = (ip_header*)eth_payload_data;
+
+ if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4));
+ ip = NULL;
+ } else {
+ hlen = IP_HEADER_LENGTH(ip);
+ ip_protocol = ip->ip_p;
+ ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
+ }
+ }
+
+ if (ip)
+ {
+ if (txdw0 & CP_TX_IPCS)
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n"));
+
+ if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
+ /* bad packet header len */
+ /* or packet too short */
+ }
+ else
+ {
+ ip->ip_sum = 0;
+ ip->ip_sum = ip_checksum(ip, hlen);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum));
+ }
+ }
+
+ if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
+ {
+#if defined (DEBUG_RTL8139)
+ int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
+#endif
+ DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n",
+ ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss));
+
+ int tcp_send_offset = 0;
+ int send_count = 0;
+
+ /* maximum IP header length is 60 bytes */
+ uint8_t saved_ip_header[60];
+
+ /* save IP header template; data area is used in tcp checksum calculation */
+ memcpy(saved_ip_header, eth_payload_data, hlen);
+
+ /* a placeholder for checksum calculation routine in tcp case */
+ uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
+ // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
+
+ /* pointer to TCP header */
+ tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
+
+ int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
+
+ /* ETH_MTU = ip header len + tcp header len + payload */
+ int tcp_data_len = ip_data_len - tcp_hlen;
+ int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
+
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n",
+ ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size));
+
+ /* note the cycle below overwrites IP header data,
+ but restores it from saved_ip_header before sending packet */
+
+ int is_last_frame = 0;
+
+ for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
+ {
+ uint16_t chunk_size = tcp_chunk_size;
+
+ /* check if this is the last frame */
+ if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
+ {
+ is_last_frame = 1;
+ chunk_size = tcp_data_len - tcp_send_offset;
+ }
+
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq)));
+
+ /* add 4 TCP pseudoheader fields */
+ /* copy IP source and destination fields */
+ memcpy(data_to_checksum, saved_ip_header + 12, 8);
+
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size));
+
+ if (tcp_send_offset)
+ {
+ memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
+ }
+
+ /* keep PUSH and FIN flags only for the last frame */
+ if (!is_last_frame)
+ {
+ TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
+ }
+
+ /* recalculate TCP checksum */
+ ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
+ p_tcpip_hdr->zeros = 0;
+ p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
+ p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
+
+ p_tcp_hdr->th_sum = 0;
+
+ int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum));
+
+ p_tcp_hdr->th_sum = tcp_checksum;
+
+ /* restore IP header */
+ memcpy(eth_payload_data, saved_ip_header, hlen);
+
+ /* set IP data length and recalculate IP checksum */
+ ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
+
+ /* increment IP id for subsequent frames */
+ ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
+
+ ip->ip_sum = 0;
+ ip->ip_sum = ip_checksum(eth_payload_data, hlen);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum));
+
+ int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size));
+ rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0);
+
+ /* add transferred count to TCP sequence number */
+ p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
+ ++send_count;
+ }
+
+ /* Stop sending this frame */
+ saved_size = 0;
+ }
+ else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n"));
+
+ /* maximum IP header length is 60 bytes */
+ uint8_t saved_ip_header[60];
+ memcpy(saved_ip_header, eth_payload_data, hlen);
+
+ uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
+ // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
+
+ /* add 4 TCP pseudoheader fields */
+ /* copy IP source and destination fields */
+ memcpy(data_to_checksum, saved_ip_header + 12, 8);
+
+ if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len));
+
+ ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
+ p_tcpip_hdr->zeros = 0;
+ p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
+ p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
+
+ tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
+
+ p_tcp_hdr->th_sum = 0;
+
+ int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum));
+
+ p_tcp_hdr->th_sum = tcp_checksum;
+ }
+ else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
+ {
+ DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len));
+
+ ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
+ p_udpip_hdr->zeros = 0;
+ p_udpip_hdr->ip_proto = IP_PROTO_UDP;
+ p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
+
+ udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
+
+ p_udp_hdr->uh_sum = 0;
+
+ int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
+ DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum));
+
+ p_udp_hdr->uh_sum = udp_checksum;
+ }
+
+ /* restore IP header */
+ memcpy(eth_payload_data, saved_ip_header, hlen);
+ }
+ }
+ }
+
+ /* update tally counter */
+ ++s->tally_counters.TxOk;
+
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size));
+
+ rtl8139_transfer_frame(s, saved_buffer, saved_size, 1);
+
+ /* restore card space if there was no recursion and reset offset */
+ if (!s->cplus_txbuffer)
+ {
+ s->cplus_txbuffer = saved_buffer;
+ s->cplus_txbuffer_len = saved_buffer_len;
+ s->cplus_txbuffer_offset = 0;
+ }
+ else
+ {
+ free(saved_buffer);
+ }
}
else
{
- ++s->currCPlusTxDesc;
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n"));
}
-#ifdef DEBUG_RTL8139
- printf("RTL8139: +++ C+ mode transmitted %d bytes from descriptor %d\n", txsize, descriptor);
-#endif
return 1;
}
/* Mark transfer completed */
if (!txcount)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", s->currCPlusTxDesc);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n",
+ s->currCPlusTxDesc));
}
else
{
/* Mark transfer completed */
if (!txcount)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc);
-#endif
+ DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc));
}
}
{
int descriptor = txRegOffset/4;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor);
-#endif
+
+ /* handle C+ transmit mode register configuration */
+
+ if (rtl8139_cp_transmitter_enabled(s))
+ {
+ DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor));
+
+ /* handle Dump Tally Counters command */
+ s->TxStatus[descriptor] = val;
+
+ if (descriptor == 0 && (val & 0x8))
+ {
+ target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
+
+ /* dump tally counters to specified memory location */
+ RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters);
+
+ /* mark dump completed */
+ s->TxStatus[0] &= ~0x8;
+ }
+
+ return;
+ }
+
+ DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor));
/* mask only reserved bits */
val &= ~0xff00c000; /* these bits are reset on write */
{
uint32_t ret = s->TxStatus[txRegOffset/4];
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret);
-#endif
+ DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret));
return ret;
}
|((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TSAD read val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret));
return ret;
}
{
uint16_t ret = s->CSCR;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: CSCR read val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret));
return ret;
}
static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
-#endif
+ DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
}
{
uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]);
-#ifdef DEBUG_RTL8139
- printf("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
-#endif
+ DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret));
return ret;
}
static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxBufPtr write val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val));
/* this value is off by 16 */
s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
-#if defined(DEBUG_RTL8139)
- printf(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-#endif
+ DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+ s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
}
static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
/* this value is off by 16 */
uint32_t ret = s->RxBufPtr - 0x10;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxBufPtr read val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret));
+
+ return ret;
+}
+
+static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
+{
+ /* this value is NOT off by 16 */
+ uint32_t ret = s->RxBufAddr;
+
+ DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret));
return ret;
}
static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxBuf write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val));
s->RxBuf = val;
{
uint32_t ret = s->RxBuf;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxBuf read val=0x%08x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret));
return ret;
}
static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: IntrMask write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0x1e00, s->IntrMask);
{
uint32_t ret = s->IntrMask;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: IntrMask read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret));
return ret;
}
static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: IntrStatus write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val));
#if 0
{
uint32_t ret = s->IntrStatus;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: IntrStatus read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret));
#if 0
static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139: MultiIntr write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val));
/* mask unwriteable bits */
val = SET_MASKED(val, 0xf000, s->MultiIntr);
{
uint32_t ret = s->MultiIntr;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: MultiIntr read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret));
return ret;
}
break;
case MediaStatus:
/* ignore */
-#ifdef DEBUG_RTL8139
- printf("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val));
break;
case HltClk:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: HltClk write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val));
if (val == 'R')
{
s->clock_enabled = 1;
break;
case TxThresh:
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ TxThresh write(b) val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val));
s->TxThresh = val;
break;
case TxPoll:
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ TxPoll write(b) val=0x%02x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val));
if (val & (1 << 7))
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ TxPoll high priority transmission (not implemented)\n");
-#endif
+ DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n"));
//rtl8139_cplus_transmit(s);
}
if (val & (1 << 6))
{
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ TxPoll normal priority transmission\n");
-#endif
+ DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n"));
rtl8139_cplus_transmit(s);
}
break;
default:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val);
-#endif
+ DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val));
break;
}
}
rtl8139_BasicModeStatus_write(s, val);
break;
case NWayAdvert:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: NWayAdvert write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val));
s->NWayAdvert = val;
break;
case NWayLPAR:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val));
break;
case NWayExpansion:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: NWayExpansion write(w) val=0x%04x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val));
s->NWayExpansion = val;
break;
rtl8139_CpCmd_write(s, val);
break;
+ case IntrMitigate:
+ rtl8139_IntrMitigate_write(s, val);
+ break;
+
default:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val);
-#endif
+ DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val));
#ifdef TARGET_WORDS_BIGENDIAN
rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff);
switch (addr)
{
case RxMissed:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxMissed clearing on write\n");
-#endif
+ DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n"));
s->RxMissed = 0;
break;
break;
case RxRingAddrLO:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: C+ RxRing low bits write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val));
s->RxRingAddrLO = val;
break;
case RxRingAddrHI:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: C+ RxRing high bits write val=0x%08x\n", val);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val));
s->RxRingAddrHI = val;
break;
+ case Timer:
+ DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n"));
+ s->TCTR = 0;
+ s->TCTR_base = qemu_get_clock(vm_clock);
+ break;
+
+ case FlashReg:
+ DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val));
+ s->TimerInt = val;
+ break;
+
default:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val);
-#endif
+ DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val));
#ifdef TARGET_WORDS_BIGENDIAN
rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff);
rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff);
case MediaStatus:
ret = 0xd0;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: MediaStatus read 0x%x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret));
break;
case HltClk:
ret = s->clock_enabled;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: HltClk read 0x%x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret));
break;
case PCIRevisionID:
- ret = 0x10;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: PCI Revision ID read 0x%x\n", ret);
-#endif
+ ret = RTL8139_PCI_REVID;
+ DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret));
break;
case TxThresh:
ret = s->TxThresh;
-#ifdef DEBUG_RTL8139
- printf("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret));
break;
case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
ret = s->TxConfig >> 24;
-#ifdef DEBUG_RTL8139
- printf("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret));
break;
default:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: not implemented read(b) addr=0x%x\n", addr);
-#endif
+ DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr));
ret = 0;
break;
}
ret = rtl8139_RxBufPtr_read(s);
break;
+ case RxBufAddr:
+ ret = rtl8139_RxBufAddr_read(s);
+ break;
+
case BasicModeCtrl:
ret = rtl8139_BasicModeCtrl_read(s);
break;
break;
case NWayAdvert:
ret = s->NWayAdvert;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret));
break;
case NWayLPAR:
ret = s->NWayLPAR;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret));
break;
case NWayExpansion:
ret = s->NWayExpansion;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret));
break;
case CpCmd:
ret = rtl8139_CpCmd_read(s);
break;
+ case IntrMitigate:
+ ret = rtl8139_IntrMitigate_read(s);
+ break;
+
case TxSummary:
ret = rtl8139_TSAD_read(s);
break;
break;
default:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr);
-#endif
+ DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr));
#ifdef TARGET_WORDS_BIGENDIAN
ret = rtl8139_io_readb(opaque, addr) << 8;
ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
#endif
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
-#endif
+ DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret));
break;
}
case RxMissed:
ret = s->RxMissed;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: RxMissed read val=0x%08x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret));
break;
case TxConfig:
case RxRingAddrLO:
ret = s->RxRingAddrLO;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret));
break;
case RxRingAddrHI:
ret = s->RxRingAddrHI;
-#ifdef DEBUG_RTL8139
- printf("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret);
-#endif
+ DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret));
+ break;
+
+ case Timer:
+ ret = s->TCTR;
+ DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret));
+ break;
+
+ case FlashReg:
+ ret = s->TimerInt;
+ DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret));
break;
default:
-#ifdef DEBUG_RTL8139
- printf("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr);
-#endif
+ DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr));
#ifdef TARGET_WORDS_BIGENDIAN
ret = rtl8139_io_readb(opaque, addr) << 24;
ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
#endif
-#ifdef DEBUG_RTL8139
- printf("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret);
-#endif
+ DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret));
break;
}
qemu_put_8s(f, &s->eeprom.eesk);
qemu_put_8s(f, &s->eeprom.eedi);
qemu_put_8s(f, &s->eeprom.eedo);
+
+ qemu_put_be32s(f, &s->TCTR);
+ qemu_put_be32s(f, &s->TimerInt);
+ qemu_put_be64s(f, &s->TCTR_base);
+
+ RTL8139TallyCounters_save(f, &s->tally_counters);
}
static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
RTL8139State* s=(RTL8139State*)opaque;
int i;
- if (version_id != 1)
+ /* just 2 versions for now */
+ if (version_id > 2)
return -EINVAL;
+ /* saved since version 1 */
qemu_get_buffer(f, s->phys, 6);
qemu_get_buffer(f, s->mult, 8);
qemu_get_8s(f, &s->eeprom.eedi);
qemu_get_8s(f, &s->eeprom.eedo);
+ /* saved since version 2 */
+ if (version_id >= 2)
+ {
+ qemu_get_be32s(f, &s->TCTR);
+ qemu_get_be32s(f, &s->TimerInt);
+ qemu_get_be64s(f, &s->TCTR_base);
+
+ RTL8139TallyCounters_load(f, &s->tally_counters);
+ }
+ else
+ {
+ /* not saved, use default */
+ s->TCTR = 0;
+ s->TimerInt = 0;
+ s->TCTR_base = 0;
+
+ RTL8139TallyCounters_clear(&s->tally_counters);
+ }
+
return 0;
}
rtl8139_mmio_writel,
};
+static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time)
+{
+ int64_t next_time = current_time +
+ muldiv64(1, ticks_per_sec, PCI_FREQUENCY);
+ if (next_time <= current_time)
+ next_time = current_time + 1;
+ return next_time;
+}
+
+#if RTL8139_ONBOARD_TIMER
+static void rtl8139_timer(void *opaque)
+{
+ RTL8139State *s = opaque;
+
+ int is_timeout = 0;
+
+ int64_t curr_time;
+ uint32_t curr_tick;
+
+ if (!s->clock_enabled)
+ {
+ DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n"));
+ return;
+ }
+
+ curr_time = qemu_get_clock(vm_clock);
+
+ curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec);
+
+ if (s->TimerInt && curr_tick >= s->TimerInt)
+ {
+ if (s->TCTR < s->TimerInt || curr_tick < s->TCTR)
+ {
+ is_timeout = 1;
+ }
+ }
+
+ s->TCTR = curr_tick;
+
+// DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR));
+
+ if (is_timeout)
+ {
+ DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR));
+ s->IntrStatus |= PCSTimeout;
+ rtl8139_update_irq(s);
+ }
+
+ qemu_mod_timer(s->timer,
+ rtl8139_get_next_tctr_time(s,curr_time));
+}
+#endif /* RTL8139_ONBOARD_TIMER */
+
void pci_rtl8139_init(PCIBus *bus, NICInfo *nd)
{
PCIRTL8139State *d;
pci_conf[0x02] = 0x39;
pci_conf[0x03] = 0x81;
pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
- pci_conf[0x08] = 0x20; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */
+ pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */
pci_conf[0x0a] = 0x00; /* ethernet network controller */
pci_conf[0x0b] = 0x02;
pci_conf[0x0e] = 0x00; /* header_type */
s->macaddr[3],
s->macaddr[4],
s->macaddr[5]);
+
+ s->cplus_txbuffer = NULL;
+ s->cplus_txbuffer_len = 0;
+ s->cplus_txbuffer_offset = 0;
/* XXX: instance number ? */
- register_savevm("rtl8139", 0, 1, rtl8139_save, rtl8139_load, s);
+ register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s);
register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load,
&d->dev);
+
+#if RTL8139_ONBOARD_TIMER
+ s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
+
+ qemu_mod_timer(s->timer,
+ rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
+#endif /* RTL8139_ONBOARD_TIMER */
}
+
#define DMA8_AUTO 1
#define DMA8_HIGH 2
+static void continue_dma8 (SB16State *s)
+{
+ if (s->freq > 0) {
+ audsettings_t as;
+
+ s->audio_free = 0;
+
+ as.freq = s->freq;
+ as.nchannels = 1 << s->fmt_stereo;
+ as.fmt = s->fmt;
+ as.endianness = 0;
+
+ s->voice = AUD_open_out (
+ &s->card,
+ s->voice,
+ "sb16",
+ s,
+ SB_audio_callback,
+ &as
+ );
+ }
+
+ control (s, 1);
+}
+
static void dma_cmd8 (SB16State *s, int mask, int dma_len)
{
s->fmt = AUD_FMT_U8;
s->fmt_signed = 0;
s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
if (-1 == s->time_const) {
- s->freq = 11025;
+ if (s->freq <= 0)
+ s->freq = 11025;
}
else {
int tmp = (256 - s->time_const);
s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
s->block_size, s->dma_auto, s->fifo, s->highspeed);
- if (s->freq) {
- audsettings_t as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as,
- 0 /* little endian */
- );
- }
-
- control (s, 1);
+ continue_dma8 (s);
speaker (s, 1);
}
as.freq = s->freq;
as.nchannels = 1 << s->fmt_stereo;
as.fmt = s->fmt;
+ as.endianness = 0;
s->voice = AUD_open_out (
&s->card,
"sb16",
s,
SB_audio_callback,
- &as,
- 0 /* little endian */
+ &as
);
}
break;
case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
- control (s, 1);
+ dma_cmd8 (s, DMA8_AUTO, -1);
break;
case 0x20: /* Direct ADC, Juice/PL */
break;
case 0xd4: /* continue DMA operation. 8bit */
- control (s, 1);
+ /* KQ6 (or maybe Sierras audblst.drv in general) resets
+ the frequency between halt/continue */
+ continue_dma8 (s);
break;
case 0xd5: /* halt DMA operation. 16bit */
);
}
}
- ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks);
+ ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
}
break;
return;
}
+static void legacy_reset (SB16State *s)
+{
+ audsettings_t as;
+
+ s->freq = 11025;
+ s->fmt_signed = 0;
+ s->fmt_bits = 8;
+ s->fmt_stereo = 0;
+
+ as.freq = s->freq;
+ as.nchannels = 1;
+ as.fmt = AUD_FMT_U8;
+ as.endianness = 0;
+
+ s->voice = AUD_open_out (
+ &s->card,
+ s->voice,
+ "sb16",
+ s,
+ SB_audio_callback,
+ &as
+ );
+
+ /* Not sure about that... */
+ /* AUD_set_active_out (s->voice, 1); */
+}
+
static void reset (SB16State *s)
{
pic_set_irq (s->irq, 0);
dsp_out_data(s, 0xaa);
speaker (s, 0);
control (s, 0);
+ legacy_reset (s);
}
static IO_WRITE_PROTO (dsp_write)
as.freq = s->freq;
as.nchannels = 1 << s->fmt_stereo;
as.fmt = s->fmt;
+ as.endianness = 0;
s->voice = AUD_open_out (
&s->card,
"sb16",
s,
SB_audio_callback,
- &as,
- 0 /* little endian */
+ &as
);
}
--- /dev/null
+/*
+ * SCSI Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Based on code by Fabrice Bellard
+ *
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+//#define DEBUG_SCSI
+
+#ifdef DEBUG_SCSI
+#define DPRINTF(fmt, args...) \
+do { printf("scsi-disk: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
+
+#include "vl.h"
+
+#define SENSE_NO_SENSE 0
+#define SENSE_ILLEGAL_REQUEST 5
+
+struct SCSIDevice
+{
+ int command;
+ uint32_t tag;
+ BlockDriverState *bdrv;
+ /* The qemu block layer uses a fixed 512 byte sector size.
+ This is the number of 512 byte blocks in a single scsi sector. */
+ int cluster_size;
+ /* When transfering data buf_pos and buf_len contain a partially
+ transferred block of data (or response to a command), and
+ sector/sector_count identify any remaining sectors.
+ Both sector and sector_count are in terms of qemu 512 byte blocks. */
+ /* ??? We should probably keep track of whether the data trasfer is
+ a read or a write. Currently we rely on the host getting it right. */
+ int sector;
+ int sector_count;
+ int buf_pos;
+ int buf_len;
+ int sense;
+ char buf[512];
+ scsi_completionfn completion;
+ void *opaque;
+};
+
+static void scsi_command_complete(SCSIDevice *s, int sense)
+{
+ s->sense = sense;
+ s->completion(s->opaque, s->tag, sense);
+}
+
+/* Read data from a scsi device. Returns nonzero on failure. */
+int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
+{
+ uint32_t n;
+
+ DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count);
+ if (s->buf_len == 0 && s->sector_count == 0)
+ return 1;
+
+ if (s->buf_len) {
+ n = s->buf_len;
+ if (n > len)
+ n = len;
+ memcpy(data, s->buf + s->buf_pos, n);
+ s->buf_pos += n;
+ s->buf_len -= n;
+ data += n;
+ len -= n;
+ if (s->buf_len == 0)
+ s->buf_pos = 0;
+ }
+
+ n = len / 512;
+ if (n > s->sector_count)
+ n = s->sector_count;
+
+ if (n != 0) {
+ bdrv_read(s->bdrv, s->sector, data, n);
+ data += n * 512;
+ len -= n * 512;
+ s->sector += n;
+ s->sector_count -= n;
+ }
+
+ if (len && s->sector_count) {
+ bdrv_read(s->bdrv, s->sector, s->buf, 1);
+ s->sector++;
+ s->sector_count--;
+ s->buf_pos = 0;
+ s->buf_len = 512;
+ /* Recurse to complete the partial read. */
+ return scsi_read_data(s, data, len);
+ }
+
+ if (len != 0)
+ return 1;
+
+ if (s->buf_len == 0 && s->sector_count == 0)
+ scsi_command_complete(s, SENSE_NO_SENSE);
+
+ return 0;
+}
+
+/* Read data to a scsi device. Returns nonzero on failure. */
+int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
+{
+ uint32_t n;
+
+ DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count);
+ if (s->buf_pos != 0) {
+ BADF("Bad state on write\n");
+ return 1;
+ }
+
+ if (s->sector_count == 0)
+ return 1;
+
+ if (s->buf_len != 0 || len < 512) {
+ n = 512 - s->buf_len;
+ if (n > len)
+ n = len;
+
+ memcpy(s->buf + s->buf_len, data, n);
+ data += n;
+ s->buf_len += n;
+ len -= n;
+ if (s->buf_len == 512) {
+ /* A full sector has been accumulated. Write it to disk. */
+ bdrv_write(s->bdrv, s->sector, s->buf, 1);
+ s->buf_len = 0;
+ s->sector++;
+ s->sector_count--;
+ }
+ }
+
+ n = len / 512;
+ if (n > s->sector_count)
+ n = s->sector_count;
+
+ if (n != 0) {
+ bdrv_write(s->bdrv, s->sector, data, n);
+ data += n * 512;
+ len -= n * 512;
+ s->sector += n;
+ s->sector_count -= n;
+ }
+
+ if (len >= 512)
+ return 1;
+
+ if (len && s->sector_count) {
+ /* Recurse to complete the partial write. */
+ return scsi_write_data(s, data, len);
+ }
+
+ if (len != 0)
+ return 1;
+
+ if (s->sector_count == 0)
+ scsi_command_complete(s, SENSE_NO_SENSE);
+
+ return 0;
+}
+
+/* Execute a scsi command. Returns the length of the data expected by the
+ command. This will be Positive for data transfers from the device
+ (eg. disk reads), negative for transfers to the device (eg. disk writes),
+ and zero if the command does not transfer any data. */
+
+int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
+{
+ int64_t nb_sectors;
+ uint32_t lba;
+ uint32_t len;
+ int cmdlen;
+ int is_write;
+
+ s->command = buf[0];
+ s->tag = tag;
+ s->sector_count = 0;
+ s->buf_pos = 0;
+ s->buf_len = 0;
+ is_write = 0;
+ DPRINTF("Command: 0x%02x", buf[0]);
+ switch (s->command >> 5) {
+ case 0:
+ lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
+ len = buf[4];
+ cmdlen = 6;
+ break;
+ case 1:
+ case 2:
+ lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+ len = buf[8] | (buf[7] << 8);
+ cmdlen = 10;
+ break;
+ case 4:
+ lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+ len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
+ cmdlen = 16;
+ break;
+ case 5:
+ lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+ len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
+ cmdlen = 12;
+ break;
+ default:
+ BADF("Unsupported command length, command %x\n", s->command);
+ goto fail;
+ }
+#ifdef DEBUG_SCSI
+ {
+ int i;
+ for (i = 1; i < cmdlen; i++) {
+ printf(" 0x%02x", buf[i]);
+ }
+ printf("\n");
+ }
+#endif
+ if (lun || buf[1] >> 5) {
+ /* Only LUN 0 supported. */
+ DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
+ goto fail;
+ }
+ switch (s->command) {
+ case 0x0:
+ DPRINTF("Test Unit Ready\n");
+ break;
+ case 0x03:
+ DPRINTF("Request Sense (len %d)\n", len);
+ if (len < 4)
+ goto fail;
+ memset(buf, 0, 4);
+ s->buf[0] = 0xf0;
+ s->buf[1] = 0;
+ s->buf[2] = s->sense;
+ s->buf_len = 4;
+ break;
+ case 0x12:
+ DPRINTF("Inquiry (len %d)\n", len);
+ if (len < 36) {
+ BADF("Inquiry buffer too small (%d)\n", len);
+ }
+ memset(s->buf, 0, 36);
+ if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ s->buf[0] = 5;
+ s->buf[1] = 0x80;
+ memcpy(&s->buf[16], "QEMU CD-ROM ", 16);
+ } else {
+ s->buf[0] = 0;
+ memcpy(&s->buf[16], "QEMU HARDDISK ", 16);
+ }
+ memcpy(&s->buf[8], "QEMU ", 8);
+ memcpy(&s->buf[32], QEMU_VERSION, 4);
+ /* Identify device as SCSI-3 rev 1.
+ Some later commands are also implemented. */
+ s->buf[2] = 3;
+ s->buf[3] = 2; /* Format 2 */
+ s->buf[4] = 32;
+ s->buf_len = 36;
+ break;
+ case 0x16:
+ DPRINTF("Reserve(6)\n");
+ if (buf[1] & 1)
+ goto fail;
+ break;
+ case 0x17:
+ DPRINTF("Release(6)\n");
+ if (buf[1] & 1)
+ goto fail;
+ break;
+ case 0x1a:
+ case 0x5a:
+ {
+ char *p;
+ int page;
+
+ page = buf[2] & 0x3f;
+ DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
+ p = s->buf;
+ memset(p, 0, 4);
+ s->buf[1] = 0; /* Default media type. */
+ s->buf[3] = 0; /* Block descriptor length. */
+ if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ s->buf[2] = 0x80; /* Readonly. */
+ }
+ p += 4;
+ if ((page == 8 || page == 0x3f)) {
+ /* Caching page. */
+ p[0] = 8;
+ p[1] = 0x12;
+ p[2] = 4; /* WCE */
+ p += 19;
+ }
+ if ((page == 0x3f || page == 0x2a)
+ && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
+ /* CD Capabilities and Mechanical Status page. */
+ p[0] = 0x2a;
+ p[1] = 0x14;
+ p[2] = 3; // CD-R & CD-RW read
+ p[3] = 0; // Writing not supported
+ p[4] = 0x7f; /* Audio, composite, digital out,
+ mode 2 form 1&2, multi session */
+ p[5] = 0xff; /* CD DA, DA accurate, RW supported,
+ RW corrected, C2 errors, ISRC,
+ UPC, Bar code */
+ p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0);
+ /* Locking supported, jumper present, eject, tray */
+ p[7] = 0; /* no volume & mute control, no
+ changer */
+ p[8] = (50 * 176) >> 8; // 50x read speed
+ p[9] = (50 * 176) & 0xff;
+ p[10] = 0 >> 8; // No volume
+ p[11] = 0 & 0xff;
+ p[12] = 2048 >> 8; // 2M buffer
+ p[13] = 2048 & 0xff;
+ p[14] = (16 * 176) >> 8; // 16x read speed current
+ p[15] = (16 * 176) & 0xff;
+ p[18] = (16 * 176) >> 8; // 16x write speed
+ p[19] = (16 * 176) & 0xff;
+ p[20] = (16 * 176) >> 8; // 16x write speed current
+ p[21] = (16 * 176) & 0xff;
+ p += 21;
+ }
+ s->buf_len = p - s->buf;
+ s->buf[0] = s->buf_len - 4;
+ if (s->buf_len > len)
+ s->buf_len = len;
+ }
+ break;
+ case 0x1b:
+ DPRINTF("Start Stop Unit\n");
+ break;
+ case 0x1e:
+ DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
+ bdrv_set_locked(s->bdrv, buf[4] & 1);
+ break;
+ case 0x25:
+ DPRINTF("Read Capacity\n");
+ /* The normal LEN field for this command is zero. */
+ memset(s->buf, 0, 8);
+ bdrv_get_geometry(s->bdrv, &nb_sectors);
+ s->buf[0] = (nb_sectors >> 24) & 0xff;
+ s->buf[1] = (nb_sectors >> 16) & 0xff;
+ s->buf[2] = (nb_sectors >> 8) & 0xff;
+ s->buf[3] = nb_sectors & 0xff;
+ s->buf[4] = 0;
+ s->buf[5] = 0;
+ s->buf[6] = s->cluster_size * 2;
+ s->buf[7] = 0;
+ s->buf_len = 8;
+ break;
+ case 0x08:
+ case 0x28:
+ DPRINTF("Read (sector %d, count %d)\n", lba, len);
+ s->sector = lba * s->cluster_size;
+ s->sector_count = len * s->cluster_size;
+ break;
+ case 0x0a:
+ case 0x2a:
+ DPRINTF("Write (sector %d, count %d)\n", lba, len);
+ s->sector = lba * s->cluster_size;
+ s->sector_count = len * s->cluster_size;
+ is_write = 1;
+ break;
+ case 0x35:
+ DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
+ bdrv_flush(s->bdrv);
+ break;
+ case 0x43:
+ {
+ int start_track, format, msf, toclen;
+
+ msf = buf[1] & 2;
+ format = buf[2] & 0xf;
+ start_track = buf[6];
+ bdrv_get_geometry(s->bdrv, &nb_sectors);
+ DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
+ switch(format) {
+ case 0:
+ toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
+ break;
+ case 1:
+ /* multi session : only a single session defined */
+ toclen = 12;
+ memset(s->buf, 0, 12);
+ s->buf[1] = 0x0a;
+ s->buf[2] = 0x01;
+ s->buf[3] = 0x01;
+ break;
+ case 2:
+ toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
+ break;
+ default:
+ goto error_cmd;
+ }
+ if (toclen > 0) {
+ if (len > toclen)
+ len = toclen;
+ s->buf_len = len;
+ break;
+ }
+ error_cmd:
+ DPRINTF("Read TOC error\n");
+ goto fail;
+ }
+ case 0x46:
+ DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
+ memset(s->buf, 0, 8);
+ /* ??? This shoud probably return much more information. For now
+ just return the basic header indicating the CD-ROM profile. */
+ s->buf[7] = 8; // CD-ROM
+ s->buf_len = 8;
+ break;
+ case 0x56:
+ DPRINTF("Reserve(10)\n");
+ if (buf[1] & 3)
+ goto fail;
+ break;
+ case 0x57:
+ DPRINTF("Release(10)\n");
+ if (buf[1] & 3)
+ goto fail;
+ break;
+ case 0xa0:
+ DPRINTF("Report LUNs (len %d)\n", len);
+ if (len < 16)
+ goto fail;
+ memset(s->buf, 0, 16);
+ s->buf[3] = 8;
+ s->buf_len = 16;
+ break;
+ default:
+ DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
+ fail:
+ scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
+ return 0;
+ }
+ if (s->sector_count == 0 && s->buf_len == 0) {
+ scsi_command_complete(s, SENSE_NO_SENSE);
+ }
+ len = s->sector_count * 512 + s->buf_len;
+ return is_write ? -len : len;
+}
+
+void scsi_disk_destroy(SCSIDevice *s)
+{
+ bdrv_close(s->bdrv);
+ qemu_free(s);
+}
+
+SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
+ scsi_completionfn completion,
+ void *opaque)
+{
+ SCSIDevice *s;
+
+ s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
+ s->bdrv = bdrv;
+ s->completion = completion;
+ s->opaque = opaque;
+ if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+ s->cluster_size = 4;
+ } else {
+ s->cluster_size = 1;
+ }
+
+ return s;
+}
+
s->periph_freq);
if (next == now)
next = now + 1;
- fprintf(stderr, "now=%016llx, next=%016llx\n", now, next);
+ fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next);
fprintf(stderr, "timer will underflow in %f seconds\n",
(float) (next - now) / (float) ticks_per_sec);
for (i = 0; i < 32; i++) {
count = s->irq_count[i];
if (count > 0)
- term_printf("%2d: %lld\n", i, count);
+ term_printf("%2d: %" PRId64 "\n", i, count);
}
#endif
}
// Convert remaining counter ticks to CPU ticks
s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
- DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
+ DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
if (s->mode != 1)
pic_set_irq_cpu(s->irq, out, s->cpu);
#define INITRD_LOAD_ADDR 0x00800000
#define PROM_SIZE_MAX (256 * 1024)
#define PROM_ADDR 0xffd00000
-#define PROM_FILENAMEB "proll.bin"
-#define PROM_FILENAMEE "proll.elf"
+#define PROM_FILENAME "openbios-sparc32"
#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */
#define PHYS_JJ_IDPROM_OFF 0x1FD8
#define PHYS_JJ_EEPROM_SIZE 0x2000
slavio_pic_set_irq(slavio_intctl, irq, level);
}
+void pic_set_irq_new(void *opaque, int irq, int level)
+{
+ pic_set_irq(irq, level);
+}
+
void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
{
slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
(PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
ret = load_elf(buf, 0, NULL);
- if (ret < 0) {
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
- ret = load_image(buf, phys_ram_base + prom_offset);
- }
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
#define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000
#define INITRD_LOAD_ADDR 0x00300000
-#define PROM_SIZE_MAX (256 * 1024)
+#define PROM_SIZE_MAX (512 * 1024)
#define PROM_ADDR 0x1fff0000000ULL
#define APB_SPECIAL_BASE 0x1fe00000000ULL
#define APB_MEM_BASE 0x1ff00000000ULL
#define VGA_BASE (APB_MEM_BASE + 0x400000ULL)
-#define PROM_FILENAMEB "proll-sparc64.bin"
-#define PROM_FILENAMEE "proll-sparc64.elf"
+#define PROM_FILENAME "openbios-sparc64"
#define NVRAM_SIZE 0x2000
/* TSC handling */
(PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
ret = load_elf(buf, 0, NULL);
- if (ret < 0) {
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
- ret = load_image(buf, phys_ram_base + prom_offset);
- }
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
}
}
}
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE);
+ pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL);
isa_mem_base = VGA_BASE;
- vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size, 0, 0);
- cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size);
- //pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
+ pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
--- /dev/null
+/*
+ * QEMU Uninorth PCI host (for all Mac99 and newer machines)
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState UNINState;
+
+static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ UNINState *s = opaque;
+ int i;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ for (i = 11; i < 32; i++) {
+ if ((val & (1 << i)) != 0)
+ break;
+ }
+#if 0
+ s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
+#else
+ s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11);
+#endif
+}
+
+static uint32_t pci_unin_main_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ UNINState *s = opaque;
+ uint32_t val;
+ int devfn;
+
+ devfn = (s->config_reg >> 8) & 0xFF;
+ val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_unin_main_config_write[] = {
+ &pci_unin_main_config_writel,
+ &pci_unin_main_config_writel,
+ &pci_unin_main_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_main_config_read[] = {
+ &pci_unin_main_config_readl,
+ &pci_unin_main_config_readl,
+ &pci_unin_main_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_unin_main_write[] = {
+ &pci_host_data_writeb,
+ &pci_host_data_writew,
+ &pci_host_data_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_main_read[] = {
+ &pci_host_data_readb,
+ &pci_host_data_readw,
+ &pci_host_data_readl,
+};
+
+#if 0
+
+static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ UNINState *s = opaque;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ s->config_reg = 0x80000000 | (val & ~0x00000001);
+}
+
+static uint32_t pci_unin_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ UNINState *s = opaque;
+ uint32_t val;
+
+ val = (s->config_reg | 0x00000001) & ~0x80000000;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_unin_config_write[] = {
+ &pci_unin_config_writel,
+ &pci_unin_config_writel,
+ &pci_unin_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_config_read[] = {
+ &pci_unin_config_readl,
+ &pci_unin_config_readl,
+ &pci_unin_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_unin_write[] = {
+ &pci_host_pci_writeb,
+ &pci_host_pci_writew,
+ &pci_host_pci_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_read[] = {
+ &pci_host_pci_readb,
+ &pci_host_pci_readw,
+ &pci_host_pci_readl,
+};
+#endif
+
+static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_pmac_init(void *pic)
+{
+ UNINState *s;
+ PCIDevice *d;
+ int pci_mem_config, pci_mem_data;
+
+ /* Use values found on a real PowerMac */
+ /* Uninorth main bus */
+ s = qemu_mallocz(sizeof(UNINState));
+ s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3);
+
+ pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
+ pci_unin_main_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
+ pci_unin_main_write, s);
+ cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
+ d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice),
+ 11 << 3, NULL, NULL);
+ d->config[0x00] = 0x6b; // vendor_id : Apple
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x1F; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ d->config[0x34] = 0x00; // capabilities_pointer
+
+#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly
+ /* pci-to-pci bridge */
+ d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
+ NULL, NULL);
+ d->config[0x00] = 0x11; // vendor_id : TI
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x26; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x05; // revision
+ d->config[0x0A] = 0x04; // class_sub = pci2pci
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x20; // latency_timer
+ d->config[0x0E] = 0x01; // header_type
+
+ d->config[0x18] = 0x01; // primary_bus
+ d->config[0x19] = 0x02; // secondary_bus
+ d->config[0x1A] = 0x02; // subordinate_bus
+ d->config[0x1B] = 0x20; // secondary_latency_timer
+ d->config[0x1C] = 0x11; // io_base
+ d->config[0x1D] = 0x01; // io_limit
+ d->config[0x20] = 0x00; // memory_base
+ d->config[0x21] = 0x80;
+ d->config[0x22] = 0x00; // memory_limit
+ d->config[0x23] = 0x80;
+ d->config[0x24] = 0x01; // prefetchable_memory_base
+ d->config[0x25] = 0x80;
+ d->config[0x26] = 0xF1; // prefectchable_memory_limit
+ d->config[0x27] = 0x7F;
+ // d->config[0x34] = 0xdc // capabilities_pointer
+#endif
+#if 0 // XXX: not needed for now
+ /* Uninorth AGP bus */
+ s = &pci_bridge[1];
+ pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
+ pci_unin_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
+ pci_unin_write, s);
+ cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data);
+
+ d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
+ NULL, NULL);
+ d->config[0x00] = 0x6b; // vendor_id : Apple
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x20; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ // d->config[0x34] = 0x80; // capabilities_pointer
+#endif
+
+#if 0 // XXX: not needed for now
+ /* Uninorth internal bus */
+ s = &pci_bridge[2];
+ pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
+ pci_unin_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
+ pci_unin_write, s);
+ cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data);
+
+ d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
+ 3, 11 << 3, NULL, NULL);
+ d->config[0x00] = 0x6b; // vendor_id : Apple
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x1E; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ d->config[0x34] = 0x00; // capabilities_pointer
+#endif
+ return s->bus;
+}
+
return ret;
}
+static void usb_mouse_handle_destroy(USBDevice *dev)
+{
+ USBMouseState *s = (USBMouseState *)dev;
+
+ qemu_add_mouse_event_handler(NULL, NULL, 0);
+ qemu_free(s);
+}
+
USBDevice *usb_tablet_init(void)
{
USBMouseState *s;
s->dev.handle_reset = usb_mouse_handle_reset;
s->dev.handle_control = usb_mouse_handle_control;
s->dev.handle_data = usb_mouse_handle_data;
+ s->dev.handle_destroy = usb_mouse_handle_destroy;
s->kind = USB_TABLET;
+ pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
+
return (USBDevice *)s;
}
s->dev.handle_reset = usb_mouse_handle_reset;
s->dev.handle_control = usb_mouse_handle_control;
s->dev.handle_data = usb_mouse_handle_data;
+ s->dev.handle_destroy = usb_mouse_handle_destroy;
s->kind = USB_MOUSE;
+ pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
+
return (USBDevice *)s;
}
static const uint8_t qemu_hub_hub_descriptor[] =
{
- 0x09, /* u8 bLength; */
+ 0x00, /* u8 bLength; patched in later */
0x29, /* u8 bDescriptorType; Hub-descriptor */
0x00, /* u8 bNbrPorts; (patched later) */
0x0a, /* u16 wHubCharacteristics; */
else
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
port->port.dev = dev;
+ /* send the attach message */
+ dev->handle_packet(dev,
+ USB_MSG_ATTACH, 0, 0, NULL, 0);
} else {
dev = port->port.dev;
if (dev) {
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
+ /* send the detach message */
+ dev->handle_packet(dev,
+ USB_MSG_DETACH, 0, 0, NULL, 0);
port->port.dev = NULL;
}
}
}
ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
+ data[0] = ret;
break;
}
default:
return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
}
-USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
+static void usb_hub_handle_destroy(USBDevice *dev)
+{
+ USBHubState *s = (USBHubState *)dev;
+
+ qemu_free(s);
+}
+
+USBDevice *usb_hub_init(int nb_ports)
{
USBHubState *s;
USBHubPort *port;
s->dev.handle_reset = usb_hub_handle_reset;
s->dev.handle_control = usb_hub_handle_control;
s->dev.handle_data = usb_hub_handle_data;
+ s->dev.handle_destroy = usb_hub_handle_destroy;
+
+ pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub");
s->nb_ports = nb_ports;
for(i = 0; i < s->nb_ports; i++) {
port = &s->ports[i];
+ qemu_register_usb_port(&port->port, s, i, usb_hub_attach);
port->wPortStatus = PORT_STAT_POWER;
port->wPortChange = 0;
- port->port.attach = usb_hub_attach;
- port->port.opaque = s;
- port->port.index = i;
- usb_ports[i] = &port->port;
}
return (USBDevice *)s;
}
--- /dev/null
+/*
+ * USB Mass Storage Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+#include "vl.h"
+
+//#define DEBUG_MSD
+
+#ifdef DEBUG_MSD
+#define DPRINTF(fmt, args...) \
+do { printf("usb-msd: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+/* USB requests. */
+#define MassStorageReset 0xff
+#define GetMaxLun 0xfe
+
+enum USBMSDMode {
+ USB_MSDM_CBW, /* Command Block. */
+ USB_MSDM_DATAOUT, /* Tranfer data to device. */
+ USB_MSDM_DATAIN, /* Transfer data from device. */
+ USB_MSDM_CSW /* Command Status. */
+};
+
+typedef struct {
+ USBDevice dev;
+ enum USBMSDMode mode;
+ uint32_t data_len;
+ uint32_t tag;
+ SCSIDevice *scsi_dev;
+ int result;
+} MSDState;
+
+static const uint8_t qemu_msd_dev_descriptor[] = {
+ 0x12, /* u8 bLength; */
+ 0x01, /* u8 bDescriptorType; Device */
+ 0x10, 0x00, /* u16 bcdUSB; v1.0 */
+
+ 0x00, /* u8 bDeviceClass; */
+ 0x00, /* u8 bDeviceSubClass; */
+ 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
+ 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
+
+ /* Vendor and product id are arbitrary. */
+ 0x00, 0x00, /* u16 idVendor; */
+ 0x00, 0x00, /* u16 idProduct; */
+ 0x00, 0x00, /* u16 bcdDevice */
+
+ 0x01, /* u8 iManufacturer; */
+ 0x02, /* u8 iProduct; */
+ 0x03, /* u8 iSerialNumber; */
+ 0x01 /* u8 bNumConfigurations; */
+};
+
+static const uint8_t qemu_msd_config_descriptor[] = {
+
+ /* one configuration */
+ 0x09, /* u8 bLength; */
+ 0x02, /* u8 bDescriptorType; Configuration */
+ 0x20, 0x00, /* u16 wTotalLength; */
+ 0x01, /* u8 bNumInterfaces; (1) */
+ 0x01, /* u8 bConfigurationValue; */
+ 0x00, /* u8 iConfiguration; */
+ 0xc0, /* u8 bmAttributes;
+ Bit 7: must be set,
+ 6: Self-powered,
+ 5: Remote wakeup,
+ 4..0: resvd */
+ 0x00, /* u8 MaxPower; */
+
+ /* one interface */
+ 0x09, /* u8 if_bLength; */
+ 0x04, /* u8 if_bDescriptorType; Interface */
+ 0x00, /* u8 if_bInterfaceNumber; */
+ 0x00, /* u8 if_bAlternateSetting; */
+ 0x02, /* u8 if_bNumEndpoints; */
+ 0x08, /* u8 if_bInterfaceClass; MASS STORAGE */
+ 0x06, /* u8 if_bInterfaceSubClass; SCSI */
+ 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */
+ 0x00, /* u8 if_iInterface; */
+
+ /* Bulk-In endpoint */
+ 0x07, /* u8 ep_bLength; */
+ 0x05, /* u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x02, /* u8 ep_bmAttributes; Bulk */
+ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
+ 0x00, /* u8 ep_bInterval; */
+
+ /* Bulk-Out endpoint */
+ 0x07, /* u8 ep_bLength; */
+ 0x05, /* u8 ep_bDescriptorType; Endpoint */
+ 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */
+ 0x02, /* u8 ep_bmAttributes; Bulk */
+ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */
+ 0x00 /* u8 ep_bInterval; */
+};
+
+static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail)
+{
+ MSDState *s = (MSDState *)opaque;
+
+ DPRINTF("Command complete\n");
+ s->result = fail;
+ s->mode = USB_MSDM_CSW;
+}
+
+static void usb_msd_handle_reset(USBDevice *dev)
+{
+ MSDState *s = (MSDState *)dev;
+
+ DPRINTF("Reset\n");
+ s->mode = USB_MSDM_CBW;
+}
+
+static int usb_msd_handle_control(USBDevice *dev, int request, int value,
+ int index, int length, uint8_t *data)
+{
+ MSDState *s = (MSDState *)dev;
+ int ret = 0;
+
+ switch (request) {
+ case DeviceRequest | USB_REQ_GET_STATUS:
+ data[0] = (1 << USB_DEVICE_SELF_POWERED) |
+ (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+ data[1] = 0x00;
+ ret = 2;
+ break;
+ case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+ if (value == USB_DEVICE_REMOTE_WAKEUP) {
+ dev->remote_wakeup = 0;
+ } else {
+ goto fail;
+ }
+ ret = 0;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_FEATURE:
+ if (value == USB_DEVICE_REMOTE_WAKEUP) {
+ dev->remote_wakeup = 1;
+ } else {
+ goto fail;
+ }
+ ret = 0;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+ dev->addr = value;
+ ret = 0;
+ break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ switch(value >> 8) {
+ case USB_DT_DEVICE:
+ memcpy(data, qemu_msd_dev_descriptor,
+ sizeof(qemu_msd_dev_descriptor));
+ ret = sizeof(qemu_msd_dev_descriptor);
+ break;
+ case USB_DT_CONFIG:
+ memcpy(data, qemu_msd_config_descriptor,
+ sizeof(qemu_msd_config_descriptor));
+ ret = sizeof(qemu_msd_config_descriptor);
+ break;
+ case USB_DT_STRING:
+ switch(value & 0xff) {
+ case 0:
+ /* language ids */
+ data[0] = 4;
+ data[1] = 3;
+ data[2] = 0x09;
+ data[3] = 0x04;
+ ret = 4;
+ break;
+ case 1:
+ /* vendor description */
+ ret = set_usb_string(data, "QEMU " QEMU_VERSION);
+ break;
+ case 2:
+ /* product description */
+ ret = set_usb_string(data, "QEMU USB HARDDRIVE");
+ break;
+ case 3:
+ /* serial number */
+ ret = set_usb_string(data, "1");
+ break;
+ default:
+ goto fail;
+ }
+ break;
+ default:
+ goto fail;
+ }
+ break;
+ case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+ data[0] = 1;
+ ret = 1;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ ret = 0;
+ break;
+ case DeviceRequest | USB_REQ_GET_INTERFACE:
+ data[0] = 0;
+ ret = 1;
+ break;
+ case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+ ret = 0;
+ break;
+ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+ if (value == 0 && index != 0x81) { /* clear ep halt */
+ goto fail;
+ }
+ ret = 0;
+ break;
+ /* Class specific requests. */
+ case MassStorageReset:
+ /* Reset state ready for the next CBW. */
+ s->mode = USB_MSDM_CBW;
+ ret = 0;
+ break;
+ case GetMaxLun:
+ data[0] = 0;
+ ret = 1;
+ break;
+ default:
+ fail:
+ ret = USB_RET_STALL;
+ break;
+ }
+ return ret;
+}
+
+struct usb_msd_cbw {
+ uint32_t sig;
+ uint32_t tag;
+ uint32_t data_len;
+ uint8_t flags;
+ uint8_t lun;
+ uint8_t cmd_len;
+ uint8_t cmd[16];
+};
+
+struct usb_msd_csw {
+ uint32_t sig;
+ uint32_t tag;
+ uint32_t residue;
+ uint8_t status;
+};
+
+static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep,
+ uint8_t *data, int len)
+{
+ MSDState *s = (MSDState *)dev;
+ int ret = 0;
+ struct usb_msd_cbw cbw;
+ struct usb_msd_csw csw;
+
+ switch (pid) {
+ case USB_TOKEN_OUT:
+ if (devep != 2)
+ goto fail;
+
+ switch (s->mode) {
+ case USB_MSDM_CBW:
+ if (len != 31) {
+ fprintf(stderr, "usb-msd: Bad CBW size");
+ goto fail;
+ }
+ memcpy(&cbw, data, 31);
+ if (le32_to_cpu(cbw.sig) != 0x43425355) {
+ fprintf(stderr, "usb-msd: Bad signature %08x\n",
+ le32_to_cpu(cbw.sig));
+ goto fail;
+ }
+ DPRINTF("Command on LUN %d\n", cbw.lun);
+ if (cbw.lun != 0) {
+ fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
+ goto fail;
+ }
+ s->tag = le32_to_cpu(cbw.tag);
+ s->data_len = le32_to_cpu(cbw.data_len);
+ if (s->data_len == 0) {
+ s->mode = USB_MSDM_CSW;
+ } else if (cbw.flags & 0x80) {
+ s->mode = USB_MSDM_DATAIN;
+ } else {
+ s->mode = USB_MSDM_DATAOUT;
+ }
+ DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
+ s->tag, cbw.flags, cbw.cmd_len, s->data_len);
+ scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
+ ret = len;
+ break;
+
+ case USB_MSDM_DATAOUT:
+ DPRINTF("Data out %d/%d\n", len, s->data_len);
+ if (len > s->data_len)
+ goto fail;
+
+ if (scsi_write_data(s->scsi_dev, data, len))
+ goto fail;
+
+ s->data_len -= len;
+ if (s->data_len == 0)
+ s->mode = USB_MSDM_CSW;
+ ret = len;
+ break;
+
+ default:
+ DPRINTF("Unexpected write (len %d)\n", len);
+ goto fail;
+ }
+ break;
+
+ case USB_TOKEN_IN:
+ if (devep != 1)
+ goto fail;
+
+ switch (s->mode) {
+ case USB_MSDM_CSW:
+ DPRINTF("Command status %d tag 0x%x, len %d\n",
+ s->result, s->tag, len);
+ if (len < 13)
+ goto fail;
+
+ csw.sig = cpu_to_le32(0x53425355);
+ csw.tag = cpu_to_le32(s->tag);
+ csw.residue = 0;
+ csw.status = s->result;
+ memcpy(data, &csw, 13);
+ ret = 13;
+ s->mode = USB_MSDM_CBW;
+ break;
+
+ case USB_MSDM_DATAIN:
+ DPRINTF("Data in %d/%d\n", len, s->data_len);
+ if (len > s->data_len)
+ len = s->data_len;
+
+ if (scsi_read_data(s->scsi_dev, data, len))
+ goto fail;
+
+ s->data_len -= len;
+ if (s->data_len == 0)
+ s->mode = USB_MSDM_CSW;
+ ret = len;
+ break;
+
+ default:
+ DPRINTF("Unexpected read (len %d)\n", len);
+ goto fail;
+ }
+ break;
+
+ default:
+ DPRINTF("Bad token\n");
+ fail:
+ ret = USB_RET_STALL;
+ break;
+ }
+
+ return ret;
+}
+
+static void usb_msd_handle_destroy(USBDevice *dev)
+{
+ MSDState *s = (MSDState *)dev;
+
+ scsi_disk_destroy(s->scsi_dev);
+ qemu_free(s);
+}
+
+USBDevice *usb_msd_init(const char *filename)
+{
+ MSDState *s;
+ BlockDriverState *bdrv;
+
+ s = qemu_mallocz(sizeof(MSDState));
+ if (!s)
+ return NULL;
+
+ bdrv = bdrv_new("usb");
+ bdrv_open(bdrv, filename, 0);
+
+ s->dev.speed = USB_SPEED_FULL;
+ s->dev.handle_packet = usb_generic_handle_packet;
+
+ s->dev.handle_reset = usb_msd_handle_reset;
+ s->dev.handle_control = usb_msd_handle_control;
+ s->dev.handle_data = usb_msd_handle_data;
+ s->dev.handle_destroy = usb_msd_handle_destroy;
+
+ snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
+ filename);
+
+ s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s);
+ usb_msd_handle_reset((USBDevice *)s);
+ return (USBDevice *)s;
+}
--- /dev/null
+/*
+ * QEMU USB OHCI Emulation
+ * Copyright (c) 2004 Gianni Tedesco
+ * Copyright (c) 2006 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * TODO:
+ * o Isochronous transfers
+ * o Allocate bandwidth in frames properly
+ * o Disable timers when nothing needs to be done, or remove timer usage
+ * all together.
+ * o Handle unrecoverable errors properly
+ * o BIOS work to boot from USB storage
+*/
+
+#include "vl.h"
+
+//#define DEBUG_OHCI
+/* Dump packet contents. */
+//#define DEBUG_PACKET
+/* This causes frames to occur 1000x slower */
+//#define OHCI_TIME_WARP 1
+
+#ifdef DEBUG_OHCI
+#define dprintf printf
+#else
+#define dprintf(...)
+#endif
+
+/* Number of Downstream Ports on the root hub. */
+
+#define OHCI_MAX_PORTS 15
+
+static int64_t usb_frame_time;
+static int64_t usb_bit_time;
+
+typedef struct OHCIPort {
+ USBPort port;
+ uint32_t ctrl;
+} OHCIPort;
+
+typedef struct {
+ struct PCIDevice pci_dev;
+ target_phys_addr_t mem_base;
+ int mem;
+ int num_ports;
+
+ QEMUTimer *eof_timer;
+ int64_t sof_time;
+
+ /* OHCI state */
+ /* Control partition */
+ uint32_t ctl, status;
+ uint32_t intr_status;
+ uint32_t intr;
+
+ /* memory pointer partition */
+ uint32_t hcca;
+ uint32_t ctrl_head, ctrl_cur;
+ uint32_t bulk_head, bulk_cur;
+ uint32_t per_cur;
+ uint32_t done;
+ int done_count;
+
+ /* Frame counter partition */
+ uint32_t fsmps:15;
+ uint32_t fit:1;
+ uint32_t fi:14;
+ uint32_t frt:1;
+ uint16_t frame_number;
+ uint16_t padding;
+ uint32_t pstart;
+ uint32_t lst;
+
+ /* Root Hub partition */
+ uint32_t rhdesc_a, rhdesc_b;
+ uint32_t rhstatus;
+ OHCIPort rhport[OHCI_MAX_PORTS];
+} OHCIState;
+
+/* Host Controller Communications Area */
+struct ohci_hcca {
+ uint32_t intr[32];
+ uint16_t frame, pad;
+ uint32_t done;
+};
+
+/* Bitfields for the first word of an Endpoint Desciptor. */
+#define OHCI_ED_FA_SHIFT 0
+#define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT)
+#define OHCI_ED_EN_SHIFT 7
+#define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT)
+#define OHCI_ED_D_SHIFT 11
+#define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT)
+#define OHCI_ED_S (1<<13)
+#define OHCI_ED_K (1<<14)
+#define OHCI_ED_F (1<<15)
+#define OHCI_ED_MPS_SHIFT 7
+#define OHCI_ED_MPS_MASK (0xf<<OHCI_ED_FA_SHIFT)
+
+/* Flags in the head field of an Endpoint Desciptor. */
+#define OHCI_ED_H 1
+#define OHCI_ED_C 2
+
+/* Bitfields for the first word of a Transfer Desciptor. */
+#define OHCI_TD_R (1<<18)
+#define OHCI_TD_DP_SHIFT 19
+#define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT)
+#define OHCI_TD_DI_SHIFT 21
+#define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT)
+#define OHCI_TD_T0 (1<<24)
+#define OHCI_TD_T1 (1<<24)
+#define OHCI_TD_EC_SHIFT 26
+#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT)
+#define OHCI_TD_CC_SHIFT 28
+#define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT)
+
+#define OHCI_DPTR_MASK 0xfffffff0
+
+#define OHCI_BM(val, field) \
+ (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
+
+#define OHCI_SET_BM(val, field, newval) do { \
+ val &= ~OHCI_##field##_MASK; \
+ val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
+ } while(0)
+
+/* endpoint descriptor */
+struct ohci_ed {
+ uint32_t flags;
+ uint32_t tail;
+ uint32_t head;
+ uint32_t next;
+};
+
+/* General transfer descriptor */
+struct ohci_td {
+ uint32_t flags;
+ uint32_t cbp;
+ uint32_t next;
+ uint32_t be;
+};
+
+#define USB_HZ 12000000
+
+/* OHCI Local stuff */
+#define OHCI_CTL_CBSR ((1<<0)|(1<<1))
+#define OHCI_CTL_PLE (1<<2)
+#define OHCI_CTL_IE (1<<3)
+#define OHCI_CTL_CLE (1<<4)
+#define OHCI_CTL_BLE (1<<5)
+#define OHCI_CTL_HCFS ((1<<6)|(1<<7))
+#define OHCI_USB_RESET 0x00
+#define OHCI_USB_RESUME 0x40
+#define OHCI_USB_OPERATIONAL 0x80
+#define OHCI_USB_SUSPEND 0xc0
+#define OHCI_CTL_IR (1<<8)
+#define OHCI_CTL_RWC (1<<9)
+#define OHCI_CTL_RWE (1<<10)
+
+#define OHCI_STATUS_HCR (1<<0)
+#define OHCI_STATUS_CLF (1<<1)
+#define OHCI_STATUS_BLF (1<<2)
+#define OHCI_STATUS_OCR (1<<3)
+#define OHCI_STATUS_SOC ((1<<6)|(1<<7))
+
+#define OHCI_INTR_SO (1<<0) /* Scheduling overrun */
+#define OHCI_INTR_WD (1<<1) /* HcDoneHead writeback */
+#define OHCI_INTR_SF (1<<2) /* Start of frame */
+#define OHCI_INTR_RD (1<<3) /* Resume detect */
+#define OHCI_INTR_UE (1<<4) /* Unrecoverable error */
+#define OHCI_INTR_FNO (1<<5) /* Frame number overflow */
+#define OHCI_INTR_RHSC (1<<6) /* Root hub status change */
+#define OHCI_INTR_OC (1<<30) /* Ownership change */
+#define OHCI_INTR_MIE (1<<31) /* Master Interrupt Enable */
+
+#define OHCI_HCCA_SIZE 0x100
+#define OHCI_HCCA_MASK 0xffffff00
+
+#define OHCI_EDPTR_MASK 0xfffffff0
+
+#define OHCI_FMI_FI 0x00003fff
+#define OHCI_FMI_FSMPS 0xffff0000
+#define OHCI_FMI_FIT 0x80000000
+
+#define OHCI_FR_RT (1<<31)
+
+#define OHCI_LS_THRESH 0x628
+
+#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */
+#define OHCI_RHA_PSM (1<<8)
+#define OHCI_RHA_NPS (1<<9)
+#define OHCI_RHA_DT (1<<10)
+#define OHCI_RHA_OCPM (1<<11)
+#define OHCI_RHA_NOCP (1<<12)
+#define OHCI_RHA_POTPGT_MASK 0xff000000
+
+#define OHCI_RHS_LPS (1<<0)
+#define OHCI_RHS_OCI (1<<1)
+#define OHCI_RHS_DRWE (1<<15)
+#define OHCI_RHS_LPSC (1<<16)
+#define OHCI_RHS_OCIC (1<<17)
+#define OHCI_RHS_CRWE (1<<31)
+
+#define OHCI_PORT_CCS (1<<0)
+#define OHCI_PORT_PES (1<<1)
+#define OHCI_PORT_PSS (1<<2)
+#define OHCI_PORT_POCI (1<<3)
+#define OHCI_PORT_PRS (1<<4)
+#define OHCI_PORT_PPS (1<<8)
+#define OHCI_PORT_LSDA (1<<9)
+#define OHCI_PORT_CSC (1<<16)
+#define OHCI_PORT_PESC (1<<17)
+#define OHCI_PORT_PSSC (1<<18)
+#define OHCI_PORT_OCIC (1<<19)
+#define OHCI_PORT_PRSC (1<<20)
+#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
+ |OHCI_PORT_OCIC|OHCI_PORT_PRSC)
+
+#define OHCI_TD_DIR_SETUP 0x0
+#define OHCI_TD_DIR_OUT 0x1
+#define OHCI_TD_DIR_IN 0x2
+#define OHCI_TD_DIR_RESERVED 0x3
+
+#define OHCI_CC_NOERROR 0x0
+#define OHCI_CC_CRC 0x1
+#define OHCI_CC_BITSTUFFING 0x2
+#define OHCI_CC_DATATOGGLEMISMATCH 0x3
+#define OHCI_CC_STALL 0x4
+#define OHCI_CC_DEVICENOTRESPONDING 0x5
+#define OHCI_CC_PIDCHECKFAILURE 0x6
+#define OHCI_CC_UNDEXPETEDPID 0x7
+#define OHCI_CC_DATAOVERRUN 0x8
+#define OHCI_CC_DATAUNDERRUN 0x9
+#define OHCI_CC_BUFFEROVERRUN 0xc
+#define OHCI_CC_BUFFERUNDERRUN 0xd
+
+/* Update IRQ levels */
+static inline void ohci_intr_update(OHCIState *ohci)
+{
+ int level = 0;
+
+ if ((ohci->intr & OHCI_INTR_MIE) &&
+ (ohci->intr_status & ohci->intr))
+ level = 1;
+
+ pci_set_irq(&ohci->pci_dev, 0, level);
+}
+
+/* Set an interrupt */
+static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
+{
+ ohci->intr_status |= intr;
+ ohci_intr_update(ohci);
+}
+
+/* Attach or detach a device on a root hub port. */
+static void ohci_attach(USBPort *port1, USBDevice *dev)
+{
+ OHCIState *s = port1->opaque;
+ OHCIPort *port = &s->rhport[port1->index];
+ uint32_t old_state = port->ctrl;
+
+ if (dev) {
+ if (port->port.dev) {
+ usb_attach(port1, NULL);
+ }
+ /* set connect status */
+ port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
+
+ /* update speed */
+ if (dev->speed == USB_SPEED_LOW)
+ port->ctrl |= OHCI_PORT_LSDA;
+ else
+ port->ctrl &= ~OHCI_PORT_LSDA;
+ port->port.dev = dev;
+ /* send the attach message */
+ dev->handle_packet(dev,
+ USB_MSG_ATTACH, 0, 0, NULL, 0);
+ dprintf("usb-ohci: Attached port %d\n", port1->index);
+ } else {
+ /* set connect status */
+ if (port->ctrl & OHCI_PORT_CCS) {
+ port->ctrl &= ~OHCI_PORT_CCS;
+ port->ctrl |= OHCI_PORT_CSC;
+ }
+ /* disable port */
+ if (port->ctrl & OHCI_PORT_PES) {
+ port->ctrl &= ~OHCI_PORT_PES;
+ port->ctrl |= OHCI_PORT_PESC;
+ }
+ dev = port->port.dev;
+ if (dev) {
+ /* send the detach message */
+ dev->handle_packet(dev,
+ USB_MSG_DETACH, 0, 0, NULL, 0);
+ }
+ port->port.dev = NULL;
+ dprintf("usb-ohci: Detached port %d\n", port1->index);
+ }
+
+ if (old_state != port->ctrl)
+ ohci_set_interrupt(s, OHCI_INTR_RHSC);
+}
+
+/* Reset the controller */
+static void ohci_reset(OHCIState *ohci)
+{
+ OHCIPort *port;
+ int i;
+
+ ohci->ctl = 0;
+ ohci->status = 0;
+ ohci->intr_status = 0;
+ ohci->intr = OHCI_INTR_MIE;
+
+ ohci->hcca = 0;
+ ohci->ctrl_head = ohci->ctrl_cur = 0;
+ ohci->bulk_head = ohci->bulk_cur = 0;
+ ohci->per_cur = 0;
+ ohci->done = 0;
+ ohci->done_count = 7;
+
+ /* FSMPS is marked TBD in OCHI 1.0, what gives ffs?
+ * I took the value linux sets ...
+ */
+ ohci->fsmps = 0x2778;
+ ohci->fi = 0x2edf;
+ ohci->fit = 0;
+ ohci->frt = 0;
+ ohci->frame_number = 0;
+ ohci->pstart = 0;
+ ohci->lst = OHCI_LS_THRESH;
+
+ ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports;
+ ohci->rhdesc_b = 0x0; /* Impl. specific */
+ ohci->rhstatus = 0;
+
+ for (i = 0; i < ohci->num_ports; i++)
+ {
+ port = &ohci->rhport[i];
+ port->ctrl = 0;
+ if (port->port.dev)
+ ohci_attach(&port->port, port->port.dev);
+ }
+ dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name);
+}
+
+/* Get an array of dwords from main memory */
+static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+ cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
+ *buf = le32_to_cpu(*buf);
+ }
+
+ return 1;
+}
+
+/* Put an array of dwords in to main memory */
+static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
+ uint32_t tmp = cpu_to_le32(*buf);
+ cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
+ }
+
+ return 1;
+}
+
+static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed)
+{
+ return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+}
+
+static inline int ohci_read_td(uint32_t addr, struct ohci_td *td)
+{
+ return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed)
+{
+ return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+}
+
+static inline int ohci_put_td(uint32_t addr, struct ohci_td *td)
+{
+ return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+/* Read/Write the contents of a TD from/to main memory. */
+static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
+{
+ uint32_t ptr;
+ uint32_t n;
+
+ ptr = td->cbp;
+ n = 0x1000 - (ptr & 0xfff);
+ if (n > len)
+ n = len;
+ cpu_physical_memory_rw(ptr, buf, n, write);
+ if (n == len)
+ return;
+ ptr = td->be & ~0xfffu;
+ buf += n;
+ cpu_physical_memory_rw(ptr, buf, len - n, write);
+}
+
+/* Service a transport descriptor.
+ Returns nonzero to terminate processing of this endpoint. */
+
+static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
+{
+ int dir;
+ size_t len = 0;
+ uint8_t buf[8192];
+ char *str = NULL;
+ int pid;
+ int ret;
+ int i;
+ USBDevice *dev;
+ struct ohci_td td;
+ uint32_t addr;
+ int flag_r;
+
+ addr = ed->head & OHCI_DPTR_MASK;
+ if (!ohci_read_td(addr, &td)) {
+ fprintf(stderr, "usb-ohci: TD read error at %x\n", addr);
+ return 0;
+ }
+
+ dir = OHCI_BM(ed->flags, ED_D);
+ switch (dir) {
+ case OHCI_TD_DIR_OUT:
+ case OHCI_TD_DIR_IN:
+ /* Same value. */
+ break;
+ default:
+ dir = OHCI_BM(td.flags, TD_DP);
+ break;
+ }
+
+ switch (dir) {
+ case OHCI_TD_DIR_IN:
+ str = "in";
+ pid = USB_TOKEN_IN;
+ break;
+ case OHCI_TD_DIR_OUT:
+ str = "out";
+ pid = USB_TOKEN_OUT;
+ break;
+ case OHCI_TD_DIR_SETUP:
+ str = "setup";
+ pid = USB_TOKEN_SETUP;
+ break;
+ default:
+ fprintf(stderr, "usb-ohci: Bad direction\n");
+ return 1;
+ }
+ if (td.cbp && td.be) {
+ if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
+ len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
+ } else {
+ len = (td.be - td.cbp) + 1;
+ }
+
+ if (len && dir != OHCI_TD_DIR_IN) {
+ ohci_copy_td(&td, buf, len, 0);
+ }
+ }
+
+ flag_r = (td.flags & OHCI_TD_R) != 0;
+#ifdef DEBUG_PACKET
+ dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
+ addr, len, str, flag_r, td.cbp, td.be);
+
+ if (len >= 0 && dir != OHCI_TD_DIR_IN) {
+ dprintf(" data:");
+ for (i = 0; i < len; i++)
+ printf(" %.2x", buf[i]);
+ dprintf("\n");
+ }
+#endif
+ ret = USB_RET_NODEV;
+ for (i = 0; i < ohci->num_ports; i++) {
+ dev = ohci->rhport[i].port.dev;
+ if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
+ continue;
+
+ ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA),
+ OHCI_BM(ed->flags, ED_EN), buf, len);
+ if (ret != USB_RET_NODEV)
+ break;
+ }
+#ifdef DEBUG_PACKET
+ dprintf("ret=%d\n", ret);
+#endif
+ if (ret >= 0) {
+ if (dir == OHCI_TD_DIR_IN) {
+ ohci_copy_td(&td, buf, ret, 1);
+#ifdef DEBUG_PACKET
+ dprintf(" data:");
+ for (i = 0; i < ret; i++)
+ printf(" %.2x", buf[i]);
+ dprintf("\n");
+#endif
+ } else {
+ ret = len;
+ }
+ }
+
+ /* Writeback */
+ if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
+ /* Transmission succeeded. */
+ if (ret == len) {
+ td.cbp = 0;
+ } else {
+ td.cbp += ret;
+ if ((td.cbp & 0xfff) + ret > 0xfff) {
+ td.cbp &= 0xfff;
+ td.cbp |= td.be & ~0xfff;
+ }
+ }
+ td.flags |= OHCI_TD_T1;
+ td.flags ^= OHCI_TD_T0;
+ OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
+ OHCI_SET_BM(td.flags, TD_EC, 0);
+
+ ed->head &= ~OHCI_ED_C;
+ if (td.flags & OHCI_TD_T0)
+ ed->head |= OHCI_ED_C;
+ } else {
+ if (ret >= 0) {
+ dprintf("usb-ohci: Underrun\n");
+ OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
+ } else {
+ switch (ret) {
+ case USB_RET_NODEV:
+ OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
+ case USB_RET_NAK:
+ dprintf("usb-ohci: got NAK\n");
+ return 1;
+ case USB_RET_STALL:
+ dprintf("usb-ohci: got STALL\n");
+ OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL);
+ break;
+ case USB_RET_BABBLE:
+ dprintf("usb-ohci: got BABBLE\n");
+ OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
+ break;
+ default:
+ fprintf(stderr, "usb-ohci: Bad device response %d\n", ret);
+ OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID);
+ OHCI_SET_BM(td.flags, TD_EC, 3);
+ break;
+ }
+ }
+ ed->head |= OHCI_ED_H;
+ }
+
+ /* Retire this TD */
+ ed->head &= ~OHCI_DPTR_MASK;
+ ed->head |= td.next & OHCI_DPTR_MASK;
+ td.next = ohci->done;
+ ohci->done = addr;
+ i = OHCI_BM(td.flags, TD_DI);
+ if (i < ohci->done_count)
+ ohci->done_count = i;
+ ohci_put_td(addr, &td);
+ return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
+}
+
+/* Service an endpoint list. Returns nonzero if active TD were found. */
+static int ohci_service_ed_list(OHCIState *ohci, uint32_t head)
+{
+ struct ohci_ed ed;
+ uint32_t next_ed;
+ uint32_t cur;
+ int active;
+
+ active = 0;
+
+ if (head == 0)
+ return 0;
+
+ for (cur = head; cur; cur = next_ed) {
+ if (!ohci_read_ed(cur, &ed)) {
+ fprintf(stderr, "usb-ohci: ED read error at %x\n", cur);
+ return 0;
+ }
+
+ next_ed = ed.next & OHCI_DPTR_MASK;
+
+ if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K))
+ continue;
+
+ /* Skip isochronous endpoints. */
+ if (ed.flags & OHCI_ED_F)
+ continue;
+
+ while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
+#ifdef DEBUG_PACKET
+ dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u "
+ "h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur,
+ OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
+ OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0,
+ (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
+ OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0,
+ (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
+ ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
+#endif
+ active = 1;
+
+ if (ohci_service_td(ohci, &ed))
+ break;
+ }
+
+ ohci_put_ed(cur, &ed);
+ }
+
+ return active;
+}
+
+/* Generate a SOF event, and set a timer for EOF */
+static void ohci_sof(OHCIState *ohci)
+{
+ ohci->sof_time = qemu_get_clock(vm_clock);
+ qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time);
+ ohci_set_interrupt(ohci, OHCI_INTR_SF);
+}
+
+/* Do frame processing on frame boundary */
+static void ohci_frame_boundary(void *opaque)
+{
+ OHCIState *ohci = opaque;
+ struct ohci_hcca hcca;
+
+ cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0);
+
+ /* Process all the lists at the end of the frame */
+ if (ohci->ctl & OHCI_CTL_PLE) {
+ int n;
+
+ n = ohci->frame_number & 0x1f;
+ ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]));
+ }
+ if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
+ if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head)
+ dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur);
+ if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) {
+ ohci->ctrl_cur = 0;
+ ohci->status &= ~OHCI_STATUS_CLF;
+ }
+ }
+
+ if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
+ if (!ohci_service_ed_list(ohci, ohci->bulk_head)) {
+ ohci->bulk_cur = 0;
+ ohci->status &= ~OHCI_STATUS_BLF;
+ }
+ }
+
+ /* Frame boundary, so do EOF stuf here */
+ ohci->frt = ohci->fit;
+
+ /* XXX: endianness */
+ ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
+ hcca.frame = cpu_to_le32(ohci->frame_number);
+
+ if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
+ if (!ohci->done)
+ abort();
+ if (ohci->intr & ohci->intr_status)
+ ohci->done |= 1;
+ hcca.done = cpu_to_le32(ohci->done);
+ ohci->done = 0;
+ ohci->done_count = 7;
+ ohci_set_interrupt(ohci, OHCI_INTR_WD);
+ }
+
+ if (ohci->done_count != 7 && ohci->done_count != 0)
+ ohci->done_count--;
+
+ /* Do SOF stuff here */
+ ohci_sof(ohci);
+
+ /* Writeback HCCA */
+ cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1);
+}
+
+/* Start sending SOF tokens across the USB bus, lists are processed in
+ * next frame
+ */
+static int ohci_bus_start(OHCIState *ohci)
+{
+ ohci->eof_timer = qemu_new_timer(vm_clock,
+ ohci_frame_boundary,
+ ohci);
+
+ if (ohci->eof_timer == NULL) {
+ fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n",
+ ohci->pci_dev.name);
+ /* TODO: Signal unrecoverable error */
+ return 0;
+ }
+
+ dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name);
+
+ ohci_sof(ohci);
+
+ return 1;
+}
+
+/* Stop sending SOF tokens on the bus */
+static void ohci_bus_stop(OHCIState *ohci)
+{
+ if (ohci->eof_timer)
+ qemu_del_timer(ohci->eof_timer);
+}
+
+/* Sets a flag in a port status register but only set it if the port is
+ * connected, if not set ConnectStatusChange flag. If flag is enabled
+ * return 1.
+ */
+static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
+{
+ int ret = 1;
+
+ /* writing a 0 has no effect */
+ if (val == 0)
+ return 0;
+
+ /* If CurrentConnectStatus is cleared we set
+ * ConnectStatusChange
+ */
+ if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
+ ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
+ if (ohci->rhstatus & OHCI_RHS_DRWE) {
+ /* TODO: CSC is a wakeup event */
+ }
+ return 0;
+ }
+
+ if (ohci->rhport[i].ctrl & val)
+ ret = 0;
+
+ /* set the bit */
+ ohci->rhport[i].ctrl |= val;
+
+ return ret;
+}
+
+/* Set the frame interval - frame interval toggle is manipulated by the hcd only */
+static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
+{
+ val &= OHCI_FMI_FI;
+
+ if (val != ohci->fi) {
+ dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n",
+ ohci->pci_dev.name, ohci->fi, ohci->fi);
+ }
+
+ ohci->fi = val;
+}
+
+static void ohci_port_power(OHCIState *ohci, int i, int p)
+{
+ if (p) {
+ ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
+ } else {
+ ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS|
+ OHCI_PORT_CCS|
+ OHCI_PORT_PSS|
+ OHCI_PORT_PRS);
+ }
+}
+
+/* Set HcControlRegister */
+static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
+{
+ uint32_t old_state;
+ uint32_t new_state;
+
+ old_state = ohci->ctl & OHCI_CTL_HCFS;
+ ohci->ctl = val;
+ new_state = ohci->ctl & OHCI_CTL_HCFS;
+
+ /* no state change */
+ if (old_state == new_state)
+ return;
+
+ switch (new_state) {
+ case OHCI_USB_OPERATIONAL:
+ ohci_bus_start(ohci);
+ break;
+ case OHCI_USB_SUSPEND:
+ ohci_bus_stop(ohci);
+ dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name);
+ break;
+ case OHCI_USB_RESUME:
+ dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name);
+ break;
+ case OHCI_USB_RESET:
+ dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name);
+ break;
+ }
+}
+
+static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
+{
+ uint16_t fr;
+ int64_t tks;
+
+ if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL)
+ return (ohci->frt << 31);
+
+ /* Being in USB operational state guarnatees sof_time was
+ * set already.
+ */
+ tks = qemu_get_clock(vm_clock) - ohci->sof_time;
+
+ /* avoid muldiv if possible */
+ if (tks >= usb_frame_time)
+ return (ohci->frt << 31);
+
+ tks = muldiv64(1, tks, usb_bit_time);
+ fr = (uint16_t)(ohci->fi - tks);
+
+ return (ohci->frt << 31) | fr;
+}
+
+
+/* Set root hub status */
+static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
+{
+ uint32_t old_state;
+
+ old_state = ohci->rhstatus;
+
+ /* write 1 to clear OCIC */
+ if (val & OHCI_RHS_OCIC)
+ ohci->rhstatus &= ~OHCI_RHS_OCIC;
+
+ if (val & OHCI_RHS_LPS) {
+ int i;
+
+ for (i = 0; i < ohci->num_ports; i++)
+ ohci_port_power(ohci, i, 0);
+ dprintf("usb-ohci: powered down all ports\n");
+ }
+
+ if (val & OHCI_RHS_LPSC) {
+ int i;
+
+ for (i = 0; i < ohci->num_ports; i++)
+ ohci_port_power(ohci, i, 1);
+ dprintf("usb-ohci: powered up all ports\n");
+ }
+
+ if (val & OHCI_RHS_DRWE)
+ ohci->rhstatus |= OHCI_RHS_DRWE;
+
+ if (val & OHCI_RHS_CRWE)
+ ohci->rhstatus &= ~OHCI_RHS_DRWE;
+
+ if (old_state != ohci->rhstatus)
+ ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
+}
+
+/* Set root hub port status */
+static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
+{
+ uint32_t old_state;
+ OHCIPort *port;
+
+ port = &ohci->rhport[portnum];
+ old_state = port->ctrl;
+
+ /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */
+ if (val & OHCI_PORT_WTC)
+ port->ctrl &= ~(val & OHCI_PORT_WTC);
+
+ if (val & OHCI_PORT_CCS)
+ port->ctrl &= ~OHCI_PORT_PES;
+
+ ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
+
+ if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS))
+ dprintf("usb-ohci: port %d: SUSPEND\n", portnum);
+
+ if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
+ dprintf("usb-ohci: port %d: RESET\n", portnum);
+ port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET,
+ 0, 0, NULL, 0);
+ port->ctrl &= ~OHCI_PORT_PRS;
+ /* ??? Should this also set OHCI_PORT_PESC. */
+ port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
+ }
+
+ /* Invert order here to ensure in ambiguous case, device is
+ * powered up...
+ */
+ if (val & OHCI_PORT_LSDA)
+ ohci_port_power(ohci, portnum, 0);
+ if (val & OHCI_PORT_PPS)
+ ohci_port_power(ohci, portnum, 1);
+
+ if (old_state != port->ctrl)
+ ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
+
+ return;
+}
+
+static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
+{
+ OHCIState *ohci = ptr;
+
+ addr -= ohci->mem_base;
+
+ /* Only aligned reads are allowed on OHCI */
+ if (addr & 3) {
+ fprintf(stderr, "usb-ohci: Mis-aligned read\n");
+ return 0xffffffff;
+ }
+
+ if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
+ /* HcRhPortStatus */
+ return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
+ }
+
+ switch (addr >> 2) {
+ case 0: /* HcRevision */
+ return 0x10;
+
+ case 1: /* HcControl */
+ return ohci->ctl;
+
+ case 2: /* HcCommandStatus */
+ return ohci->status;
+
+ case 3: /* HcInterruptStatus */
+ return ohci->intr_status;
+
+ case 4: /* HcInterruptEnable */
+ case 5: /* HcInterruptDisable */
+ return ohci->intr;
+
+ case 6: /* HcHCCA */
+ return ohci->hcca;
+
+ case 7: /* HcPeriodCurrentED */
+ return ohci->per_cur;
+
+ case 8: /* HcControlHeadED */
+ return ohci->ctrl_head;
+
+ case 9: /* HcControlCurrentED */
+ return ohci->ctrl_cur;
+
+ case 10: /* HcBulkHeadED */
+ return ohci->bulk_head;
+
+ case 11: /* HcBulkCurrentED */
+ return ohci->bulk_cur;
+
+ case 12: /* HcDoneHead */
+ return ohci->done;
+
+ case 13: /* HcFmInterval */
+ return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
+
+ case 14: /* HcFmRemaining */
+ return ohci_get_frame_remaining(ohci);
+
+ case 15: /* HcFmNumber */
+ return ohci->frame_number;
+
+ case 16: /* HcPeriodicStart */
+ return ohci->pstart;
+
+ case 17: /* HcLSThreshold */
+ return ohci->lst;
+
+ case 18: /* HcRhDescriptorA */
+ return ohci->rhdesc_a;
+
+ case 19: /* HcRhDescriptorB */
+ return ohci->rhdesc_b;
+
+ case 20: /* HcRhStatus */
+ return ohci->rhstatus;
+
+ default:
+ fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
+ return 0xffffffff;
+ }
+}
+
+static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+ OHCIState *ohci = ptr;
+
+ addr -= ohci->mem_base;
+
+ /* Only aligned reads are allowed on OHCI */
+ if (addr & 3) {
+ fprintf(stderr, "usb-ohci: Mis-aligned write\n");
+ return;
+ }
+
+ if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
+ /* HcRhPortStatus */
+ ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
+ return;
+ }
+
+ switch (addr >> 2) {
+ case 1: /* HcControl */
+ ohci_set_ctl(ohci, val);
+ break;
+
+ case 2: /* HcCommandStatus */
+ /* SOC is read-only */
+ val = (val & ~OHCI_STATUS_SOC);
+
+ /* Bits written as '0' remain unchanged in the register */
+ ohci->status |= val;
+
+ if (ohci->status & OHCI_STATUS_HCR)
+ ohci_reset(ohci);
+ break;
+
+ case 3: /* HcInterruptStatus */
+ ohci->intr_status &= ~val;
+ ohci_intr_update(ohci);
+ break;
+
+ case 4: /* HcInterruptEnable */
+ ohci->intr |= val;
+ ohci_intr_update(ohci);
+ break;
+
+ case 5: /* HcInterruptDisable */
+ ohci->intr &= ~val;
+ ohci_intr_update(ohci);
+ break;
+
+ case 6: /* HcHCCA */
+ ohci->hcca = val & OHCI_HCCA_MASK;
+ break;
+
+ case 8: /* HcControlHeadED */
+ ohci->ctrl_head = val & OHCI_EDPTR_MASK;
+ break;
+
+ case 9: /* HcControlCurrentED */
+ ohci->ctrl_cur = val & OHCI_EDPTR_MASK;
+ break;
+
+ case 10: /* HcBulkHeadED */
+ ohci->bulk_head = val & OHCI_EDPTR_MASK;
+ break;
+
+ case 11: /* HcBulkCurrentED */
+ ohci->bulk_cur = val & OHCI_EDPTR_MASK;
+ break;
+
+ case 13: /* HcFmInterval */
+ ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16;
+ ohci->fit = (val & OHCI_FMI_FIT) >> 31;
+ ohci_set_frame_interval(ohci, val);
+ break;
+
+ case 16: /* HcPeriodicStart */
+ ohci->pstart = val & 0xffff;
+ break;
+
+ case 17: /* HcLSThreshold */
+ ohci->lst = val & 0xffff;
+ break;
+
+ case 18: /* HcRhDescriptorA */
+ ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK;
+ ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK;
+ break;
+
+ case 19: /* HcRhDescriptorB */
+ break;
+
+ case 20: /* HcRhStatus */
+ ohci_set_hub_status(ohci, val);
+ break;
+
+ default:
+ fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr);
+ break;
+ }
+}
+
+/* Only dword reads are defined on OHCI register space */
+static CPUReadMemoryFunc *ohci_readfn[3]={
+ ohci_mem_read,
+ ohci_mem_read,
+ ohci_mem_read
+};
+
+/* Only dword writes are defined on OHCI register space */
+static CPUWriteMemoryFunc *ohci_writefn[3]={
+ ohci_mem_write,
+ ohci_mem_write,
+ ohci_mem_write
+};
+
+static void ohci_mapfunc(PCIDevice *pci_dev, int i,
+ uint32_t addr, uint32_t size, int type)
+{
+ OHCIState *ohci = (OHCIState *)pci_dev;
+ ohci->mem_base = addr;
+ cpu_register_physical_memory(addr, size, ohci->mem);
+}
+
+void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn)
+{
+ OHCIState *ohci;
+ int vid = 0x106b;
+ int did = 0x003f;
+ int i;
+
+
+ if (usb_frame_time == 0) {
+#if OHCI_TIME_WARP
+ usb_frame_time = ticks_per_sec;
+ usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000);
+#else
+ usb_frame_time = muldiv64(1, ticks_per_sec, 1000);
+ if (ticks_per_sec >= USB_HZ) {
+ usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ);
+ } else {
+ usb_bit_time = 1;
+ }
+#endif
+ dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n",
+ usb_frame_time, usb_bit_time);
+ }
+
+ ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
+ devfn, NULL, NULL);
+ if (ohci == NULL) {
+ fprintf(stderr, "usb-ohci: Failed to register PCI device\n");
+ return;
+ }
+
+ ohci->pci_dev.config[0x00] = vid & 0xff;
+ ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff;
+ ohci->pci_dev.config[0x02] = did & 0xff;
+ ohci->pci_dev.config[0x03] = (did >> 8) & 0xff;
+ ohci->pci_dev.config[0x09] = 0x10; /* OHCI */
+ ohci->pci_dev.config[0x0a] = 0x3;
+ ohci->pci_dev.config[0x0b] = 0xc;
+ ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
+
+ ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+
+ pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
+ PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
+
+ ohci->num_ports = num_ports;
+ for (i = 0; i < num_ports; i++) {
+ qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
+ }
+
+ ohci_reset(ohci);
+}
usb_attach(port1, NULL);
}
/* set connect status */
- if (!(port->ctrl & UHCI_PORT_CCS)) {
- port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
- }
+ port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+
/* update speed */
if (dev->speed == USB_SPEED_LOW)
port->ctrl |= UHCI_PORT_LSDA;
USB_MSG_ATTACH, 0, 0, NULL, 0);
} else {
/* set connect status */
- if (!(port->ctrl & UHCI_PORT_CCS)) {
- port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+ if (port->ctrl & UHCI_PORT_CCS) {
+ port->ctrl &= ~UHCI_PORT_CCS;
+ port->ctrl |= UHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & UHCI_PORT_EN) {
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
-void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
+void usb_uhci_init(PCIBus *bus, int devfn)
{
UHCIState *s;
uint8_t *pci_conf;
- UHCIPort *port;
int i;
s = (UHCIState *)pci_register_device(bus,
"USB-UHCI", sizeof(UHCIState),
- ((PCIDevice *)piix3_state)->devfn + 2,
- NULL, NULL);
+ devfn, NULL, NULL);
pci_conf = s->dev.config;
pci_conf[0x00] = 0x86;
pci_conf[0x01] = 0x80;
pci_conf[0x60] = 0x10; // release number
for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- port->port.opaque = s;
- port->port.index = i;
- port->port.attach = uhci_attach;
- usb_ports[i] = &port->port;
+ qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
}
s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
int (*handle_packet)(USBDevice *dev, int pid,
uint8_t devaddr, uint8_t devep,
uint8_t *data, int len);
+ void (*handle_destroy)(USBDevice *dev);
+
int speed;
/* The following fields are used by the generic USB device
int (*handle_data)(USBDevice *dev, int pid, uint8_t devep,
uint8_t *data, int len);
uint8_t addr;
+ char devname[32];
int state;
uint8_t setup_buf[8];
int setup_index;
};
+typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev);
+
/* USB port on which a device can be connected */
struct USBPort {
USBDevice *dev;
- void (*attach)(USBPort *port, USBDevice *dev);
+ usb_attachfn attach;
void *opaque;
int index; /* internal port index, may be used with the opaque */
+ struct USBPort *next; /* Used internally by qemu. */
};
void usb_attach(USBPort *port, USBDevice *dev);
int set_usb_string(uint8_t *buf, const char *str);
/* usb hub */
-USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports);
+USBDevice *usb_hub_init(int nb_ports);
/* usb-uhci.c */
-void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
+void usb_uhci_init(PCIBus *bus, int devfn);
+
+/* usb-ohci.c */
+void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn);
/* usb-linux.c */
USBDevice *usb_host_device_open(const char *devname);
/* usb-hid.c */
USBDevice *usb_mouse_init(void);
USBDevice *usb_tablet_init(void);
+
+/* usb-msd.c */
+USBDevice *usb_msd_init(const char *filename);
--- /dev/null
+/*
+ * ARM Versatile/PB PCI host controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+#include "vl.h"
+
+static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
+{
+ return addr & 0xf8ff;
+}
+
+static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
+}
+
+static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
+}
+
+static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
+}
+
+static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
+ return val;
+}
+
+static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_vpb_config_write[] = {
+ &pci_vpb_config_writeb,
+ &pci_vpb_config_writew,
+ &pci_vpb_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_vpb_config_read[] = {
+ &pci_vpb_config_readb,
+ &pci_vpb_config_readw,
+ &pci_vpb_config_readl,
+};
+
+static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ pic_set_irq_new(pic, 27 + irq_num, level);
+}
+
+PCIBus *pci_vpb_init(void *pic)
+{
+ PCIBus *s;
+ PCIDevice *d;
+ int mem_config;
+
+ s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3);
+ /* ??? Register memory space. */
+
+ mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
+ pci_vpb_config_write, s);
+ /* Selfconfig area. */
+ cpu_register_physical_memory(0x41000000, 0x10000, mem_config);
+ /* Normal config area. */
+ cpu_register_physical_memory(0x42000000, 0x10000, mem_config);
+
+ d = pci_register_device(s, "Versatile/PB PCI Controller",
+ sizeof(PCIDevice), -1, NULL, NULL);
+ d->config[0x00] = 0xee; // vendor_id
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x00; // device_id
+ d->config[0x03] = 0x03;
+ d->config[0x04] = 0x00;
+ d->config[0x05] = 0x00;
+ d->config[0x06] = 0x20;
+ d->config[0x07] = 0x02;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x09] = 0x00; // programming i/f
+ d->config[0x0A] = 0x40; // class_sub = pci host
+ d->config[0x0B] = 0x0b; // class_base = PCI_bridge
+ d->config[0x0D] = 0x10; // latency_timer
+
+ return s;
+}
+
#include "vl.h"
#include "arm_pic.h"
+#define LOCK_VALUE 0xa05f
+
/* Primary interrupt controller. */
typedef struct vpb_sic_state
return s;
}
+/* System controller. */
+
+typedef struct {
+ uint32_t base;
+ uint32_t leds;
+ uint16_t lockval;
+ uint32_t cfgdata1;
+ uint32_t cfgdata2;
+ uint32_t flags;
+ uint32_t nvflags;
+ uint32_t resetlevel;
+} vpb_sys_state;
+
+static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
+{
+ vpb_sys_state *s = (vpb_sys_state *)opaque;
+
+ offset -= s->base;
+ switch (offset) {
+ case 0x00: /* ID */
+ return 0x41007004;
+ case 0x04: /* SW */
+ /* General purpose hardware switches.
+ We don't have a useful way of exposing these to the user. */
+ return 0;
+ case 0x08: /* LED */
+ return s->leds;
+ case 0x20: /* LOCK */
+ return s->lockval;
+ case 0x0c: /* OSC0 */
+ case 0x10: /* OSC1 */
+ case 0x14: /* OSC2 */
+ case 0x18: /* OSC3 */
+ case 0x1c: /* OSC4 */
+ case 0x24: /* 100HZ */
+ /* ??? Implement these. */
+ return 0;
+ case 0x28: /* CFGDATA1 */
+ return s->cfgdata1;
+ case 0x2c: /* CFGDATA2 */
+ return s->cfgdata2;
+ case 0x30: /* FLAGS */
+ return s->flags;
+ case 0x38: /* NVFLAGS */
+ return s->nvflags;
+ case 0x40: /* RESETCTL */
+ return s->resetlevel;
+ case 0x44: /* PCICTL */
+ return 1;
+ case 0x48: /* MCI */
+ return 0;
+ case 0x4c: /* FLASH */
+ return 0;
+ case 0x50: /* CLCD */
+ return 0x1000;
+ case 0x54: /* CLCDSER */
+ return 0;
+ case 0x58: /* BOOTCS */
+ return 0;
+ case 0x5c: /* 24MHz */
+ /* ??? not implemented. */
+ return 0;
+ case 0x60: /* MISC */
+ return 0;
+ case 0x64: /* DMAPSR0 */
+ case 0x68: /* DMAPSR1 */
+ case 0x6c: /* DMAPSR2 */
+ case 0x8c: /* OSCRESET0 */
+ case 0x90: /* OSCRESET1 */
+ case 0x94: /* OSCRESET2 */
+ case 0x98: /* OSCRESET3 */
+ case 0x9c: /* OSCRESET4 */
+ case 0xc0: /* SYS_TEST_OSC0 */
+ case 0xc4: /* SYS_TEST_OSC1 */
+ case 0xc8: /* SYS_TEST_OSC2 */
+ case 0xcc: /* SYS_TEST_OSC3 */
+ case 0xd0: /* SYS_TEST_OSC4 */
+ return 0;
+ default:
+ printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
+ return 0;
+ }
+}
+
+static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
+ uint32_t val)
+{
+ vpb_sys_state *s = (vpb_sys_state *)opaque;
+ offset -= s->base;
+
+ switch (offset) {
+ case 0x08: /* LED */
+ s->leds = val;
+ case 0x0c: /* OSC0 */
+ case 0x10: /* OSC1 */
+ case 0x14: /* OSC2 */
+ case 0x18: /* OSC3 */
+ case 0x1c: /* OSC4 */
+ /* ??? */
+ break;
+ case 0x20: /* LOCK */
+ if (val == LOCK_VALUE)
+ s->lockval = val;
+ else
+ s->lockval = val & 0x7fff;
+ break;
+ case 0x28: /* CFGDATA1 */
+ /* ??? Need to implement this. */
+ s->cfgdata1 = val;
+ break;
+ case 0x2c: /* CFGDATA2 */
+ /* ??? Need to implement this. */
+ s->cfgdata2 = val;
+ break;
+ case 0x30: /* FLAGSSET */
+ s->flags |= val;
+ break;
+ case 0x34: /* FLAGSCLR */
+ s->flags &= ~val;
+ break;
+ case 0x38: /* NVFLAGSSET */
+ s->nvflags |= val;
+ break;
+ case 0x3c: /* NVFLAGSCLR */
+ s->nvflags &= ~val;
+ break;
+ case 0x40: /* RESETCTL */
+ if (s->lockval == LOCK_VALUE) {
+ s->resetlevel = val;
+ if (val & 0x100)
+ cpu_abort(cpu_single_env, "Board reset\n");
+ }
+ break;
+ case 0x44: /* PCICTL */
+ /* nothing to do. */
+ break;
+ case 0x4c: /* FLASH */
+ case 0x50: /* CLCD */
+ case 0x54: /* CLCDSER */
+ case 0x64: /* DMAPSR0 */
+ case 0x68: /* DMAPSR1 */
+ case 0x6c: /* DMAPSR2 */
+ case 0x8c: /* OSCRESET0 */
+ case 0x90: /* OSCRESET1 */
+ case 0x94: /* OSCRESET2 */
+ case 0x98: /* OSCRESET3 */
+ case 0x9c: /* OSCRESET4 */
+ break;
+ default:
+ printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
+ return;
+ }
+}
+
+static CPUReadMemoryFunc *vpb_sys_readfn[] = {
+ vpb_sys_read,
+ vpb_sys_read,
+ vpb_sys_read
+};
+
+static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
+ vpb_sys_write,
+ vpb_sys_write,
+ vpb_sys_write
+};
+
+static vpb_sys_state *vpb_sys_init(uint32_t base)
+{
+ vpb_sys_state *s;
+ int iomemtype;
+
+ s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
+ if (!s)
+ return NULL;
+ s->base = base;
+ iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
+ vpb_sys_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ /* ??? Save/restore. */
+ return s;
+}
+
/* Board init. */
/* The AB and PB boards both use the same core, just with different
CPUState *env;
void *pic;
void *sic;
+ void *scsi_hba;
+ PCIBus *pci_bus;
+ NICInfo *nd;
+ int n;
+ int done_smc = 0;
env = cpu_init();
cpu_arm_set_model(env, ARM_CPUID_ARM926);
/* SDRAM at address zero. */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ vpb_sys_init(0x10000000);
pic = arm_pic_init_cpu(env);
pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
sic = vpb_sic_init(0x10003000, pic, 31);
pl050_init(0x10006000, sic, 3, 0);
pl050_init(0x10007000, sic, 4, 1);
- /* TODO: Init PCI NICs. */
- if (nd_table[0].vlan) {
- if (nd_table[0].model == NULL
- || strcmp(nd_table[0].model, "smc91c111") == 0) {
- smc91c111_init(&nd_table[0], 0x10010000, sic, 25);
+ pci_bus = pci_vpb_init(sic);
+ /* The Versatile PCI bridge does not provide access to PCI IO space,
+ so many of the qemu PCI devices are not useable. */
+ for(n = 0; n < nb_nics; n++) {
+ nd = &nd_table[n];
+ if (!nd->model)
+ nd->model = done_smc ? "rtl8139" : "smc91c111";
+ if (strcmp(nd->model, "smc91c111") == 0) {
+ smc91c111_init(nd, 0x10010000, sic, 25);
} else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
- exit (1);
+ pci_nic_init(pci_bus, nd);
+ }
+ }
+ if (usb_enabled) {
+ usb_ohci_init(pci_bus, 3, -1);
+ }
+ scsi_hba = lsi_scsi_init(pci_bus, -1);
+ for (n = 0; n < MAX_DISKS; n++) {
+ if (bs_table[n]) {
+ lsi_scsi_attach(scsi_hba, bs_table[n], n);
}
}
VGAState *s = opaque;
uint32_t val;
- if (s->vbe_index <= VBE_DISPI_INDEX_NB)
- val = s->vbe_regs[s->vbe_index];
- else
+ if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
+ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
+ switch(s->vbe_index) {
+ /* XXX: do not hardcode ? */
+ case VBE_DISPI_INDEX_XRES:
+ val = VBE_DISPI_MAX_XRES;
+ break;
+ case VBE_DISPI_INDEX_YRES:
+ val = VBE_DISPI_MAX_YRES;
+ break;
+ case VBE_DISPI_INDEX_BPP:
+ val = VBE_DISPI_MAX_BPP;
+ break;
+ default:
+ val = s->vbe_regs[s->vbe_index];
+ break;
+ }
+ } else {
+ val = s->vbe_regs[s->vbe_index];
+ }
+ } else {
val = 0;
+ }
#ifdef DEBUG_BOCHS_VBE
printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
#endif
s->bank_offset = (val << 16);
break;
case VBE_DISPI_INDEX_ENABLE:
- if (val & VBE_DISPI_ENABLED) {
+ if ((val & VBE_DISPI_ENABLED) &&
+ !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
int h, shift_control;
s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
s->vbe_start_addr = 0;
-
+
/* clear the screen (should be done in BIOS) */
if (!(val & VBE_DISPI_NOCLEARMEM)) {
memset(s->vram_ptr, 0,
s->cr[0x13] = s->vbe_line_offset >> 3;
/* width */
s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height */
+ /* height (only meaningful if < 1024) */
h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
s->cr[0x12] = h;
s->cr[0x07] = (s->cr[0x07] & ~0x42) |
return (r << 16) | (g << 8) | b;
}
+static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
+{
+ return (b << 16) | (g << 8) | r;
+}
+
#define DEPTH 8
#include "vga_template.h"
#define DEPTH 32
#include "vga_template.h"
+#define BGR_FORMAT
+#define DEPTH 32
+#include "vga_template.h"
+
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
{
unsigned int col;
return col;
}
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32bgr(r, g, b);
+ return col;
+}
+
/* return true if the palette was modified */
static int update_palette16(VGAState *s)
{
return full_update;
}
-static inline int get_depth_index(int depth)
+#define NB_DEPTHS 5
+
+static inline int get_depth_index(DisplayState *s)
{
- switch(depth) {
+ switch(s->depth) {
default:
case 8:
return 0;
case 16:
return 2;
case 32:
- return 3;
+ if (s->bgr)
+ return 4;
+ else
+ return 3;
}
}
-static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
+static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
vga_draw_glyph8_8,
vga_draw_glyph8_16,
vga_draw_glyph8_16,
vga_draw_glyph8_32,
+ vga_draw_glyph8_32,
};
-static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
+static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
vga_draw_glyph16_8,
vga_draw_glyph16_16,
vga_draw_glyph16_16,
vga_draw_glyph16_32,
+ vga_draw_glyph16_32,
};
-static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
+static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
vga_draw_glyph9_8,
vga_draw_glyph9_16,
vga_draw_glyph9_16,
vga_draw_glyph9_32,
+ vga_draw_glyph9_32,
};
static const uint8_t cursor_glyph[32 * 4] = {
}
cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
- depth_index = get_depth_index(s->ds->depth);
+ depth_index = get_depth_index(s->ds);
if (cw == 16)
vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
else
VGA_DRAW_LINE_NB,
};
-static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
+static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
vga_draw_line2_8,
vga_draw_line2_16,
vga_draw_line2_16,
vga_draw_line2_32,
+ vga_draw_line2_32,
vga_draw_line2d2_8,
vga_draw_line2d2_16,
vga_draw_line2d2_16,
vga_draw_line2d2_32,
+ vga_draw_line2d2_32,
vga_draw_line4_8,
vga_draw_line4_16,
vga_draw_line4_16,
vga_draw_line4_32,
+ vga_draw_line4_32,
vga_draw_line4d2_8,
vga_draw_line4d2_16,
vga_draw_line4d2_16,
vga_draw_line4d2_32,
+ vga_draw_line4d2_32,
vga_draw_line8d2_8,
vga_draw_line8d2_16,
vga_draw_line8d2_16,
vga_draw_line8d2_32,
+ vga_draw_line8d2_32,
vga_draw_line8_8,
vga_draw_line8_16,
vga_draw_line8_16,
vga_draw_line8_32,
+ vga_draw_line8_32,
vga_draw_line15_8,
vga_draw_line15_15,
vga_draw_line15_16,
vga_draw_line15_32,
+ vga_draw_line15_32bgr,
vga_draw_line16_8,
vga_draw_line16_15,
vga_draw_line16_16,
vga_draw_line16_32,
+ vga_draw_line16_32bgr,
vga_draw_line24_8,
vga_draw_line24_15,
vga_draw_line24_16,
vga_draw_line24_32,
+ vga_draw_line24_32bgr,
vga_draw_line32_8,
vga_draw_line32_15,
vga_draw_line32_16,
vga_draw_line32_32,
+ vga_draw_line32_32bgr,
+};
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
+ rgb_to_pixel8_dup,
+ rgb_to_pixel15_dup,
+ rgb_to_pixel16_dup,
+ rgb_to_pixel32_dup,
+ rgb_to_pixel32bgr_dup,
};
static int vga_get_bpp(VGAState *s)
{
int width, height;
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
- height = (height + 1);
+#ifdef CONFIG_BOCHS_VBE
+ if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+ width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
+ height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
+ } else
+#endif
+ {
+ width = (s->cr[0x01] + 1) * 8;
+ height = s->cr[0x12] |
+ ((s->cr[0x07] & 0x02) << 7) |
+ ((s->cr[0x07] & 0x40) << 3);
+ height = (height + 1);
+ }
*pwidth = width;
*pheight = height;
}
break;
}
}
- vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
+ vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
if (disp_width != s->last_width ||
height != s->last_height) {
if (s->ds->depth == 0) {
/* nothing to do */
} else {
- switch(s->ds->depth) {
- case 8:
- s->rgb_to_pixel = rgb_to_pixel8_dup;
- break;
- case 15:
- s->rgb_to_pixel = rgb_to_pixel15_dup;
- break;
- default:
- case 16:
- s->rgb_to_pixel = rgb_to_pixel16_dup;
- break;
- case 32:
- s->rgb_to_pixel = rgb_to_pixel32_dup;
- break;
- }
+ s->rgb_to_pixel =
+ rgb_to_pixel_dup_table[get_depth_index(s->ds)];
full_update = 0;
if (!(s->ar_index & 0x20)) {
/* bochs VBE support */
//#define CONFIG_BOCHS_VBE
-#define VBE_DISPI_MAX_XRES 1024
-#define VBE_DISPI_MAX_YRES 768
+#define VBE_DISPI_MAX_XRES 1600
+#define VBE_DISPI_MAX_YRES 1200
+#define VBE_DISPI_MAX_BPP 32
#define VBE_DISPI_INDEX_ID 0x0
#define VBE_DISPI_INDEX_XRES 0x1
#define VBE_DISPI_DISABLED 0x00
#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_GETCAPS 0x02
+#define VBE_DISPI_8BIT_DAC 0x20
#define VBE_DISPI_LFB_ENABLED 0x40
#define VBE_DISPI_NOCLEARMEM 0x80
#endif /* !CONFIG_BOCHS_VBE */
#define CH_ATTR_SIZE (160 * 100)
-#define VGA_MAX_HEIGHT 1024
+#define VGA_MAX_HEIGHT 2048
#define VGA_STATE_COMMON \
uint8_t *vram_ptr; \
#error unsupport depth
#endif
-#if DEPTH != 15
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
uint32_t font_data,
}
}
+void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+ const uint8_t *src1,
+ int poffset, int w,
+ unsigned int color0,
+ unsigned int color1,
+ unsigned int color_xor)
+{
+ const uint8_t *plane0, *plane1;
+ int x, b0, b1;
+ uint8_t *d;
+
+ d = d1;
+ plane0 = src1;
+ plane1 = src1 + poffset;
+ for(x = 0; x < w; x++) {
+ b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
+ b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
+#if DEPTH == 8
+ switch(b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ d[0] ^= color_xor;
+ break;
+ case 2:
+ d[0] = color0;
+ break;
+ case 3:
+ d[0] = color1;
+ break;
+ }
+#elif DEPTH == 16
+ switch(b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ ((uint16_t *)d)[0] ^= color_xor;
+ break;
+ case 2:
+ ((uint16_t *)d)[0] = color0;
+ break;
+ case 3:
+ ((uint16_t *)d)[0] = color1;
+ break;
+ }
+#elif DEPTH == 32
+ switch(b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ ((uint32_t *)d)[0] ^= color_xor;
+ break;
+ case 2:
+ ((uint32_t *)d)[0] = color0;
+ break;
+ case 3:
+ ((uint32_t *)d)[0] = color1;
+ break;
+ }
+#else
+#error unsupported depth
+#endif
+ d += BPP;
+ }
+}
+
#endif /* DEPTH != 15 */
/*
* 15 bit color
*/
-static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
+static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
r = (v >> 7) & 0xf8;
g = (v >> 2) & 0xf8;
b = (v << 3) & 0xf8;
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
s += 2;
d += BPP;
} while (--w != 0);
/*
* 16 bit color
*/
-static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
+static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
r = (v >> 8) & 0xf8;
g = (v >> 3) & 0xfc;
b = (v << 3) & 0xf8;
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
s += 2;
d += BPP;
} while (--w != 0);
/*
* 24 bit color
*/
-static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d,
+static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
int w;
g = s[1];
r = s[2];
#endif
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
s += 3;
d += BPP;
} while (--w != 0);
/*
* 32 bit color
*/
-static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
+static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
const uint8_t *s, int width)
{
-#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
memcpy(d, s, width * 4);
#else
int w;
g = s[1];
r = s[2];
#endif
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+ ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
s += 4;
d += BPP;
} while (--w != 0);
#endif
}
-#if DEPTH != 15
-void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
- const uint8_t *src1,
- int poffset, int w,
- unsigned int color0,
- unsigned int color1,
- unsigned int color_xor)
-{
- const uint8_t *plane0, *plane1;
- int x, b0, b1;
- uint8_t *d;
-
- d = d1;
- plane0 = src1;
- plane1 = src1 + poffset;
- for(x = 0; x < w; x++) {
- b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
- b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
-#if DEPTH == 8
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- d[0] ^= color_xor;
- break;
- case 2:
- d[0] = color0;
- break;
- case 3:
- d[0] = color1;
- break;
- }
-#elif DEPTH == 16
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint16_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint16_t *)d)[0] = color0;
- break;
- case 3:
- ((uint16_t *)d)[0] = color1;
- break;
- }
-#elif DEPTH == 32
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint32_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint32_t *)d)[0] = color0;
- break;
- case 3:
- ((uint32_t *)d)[0] = color1;
- break;
- }
-#else
-#error unsupported depth
-#endif
- d += BPP;
- }
-}
-#endif
-
#undef PUT_PIXEL2
#undef DEPTH
#undef BPP
#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
static void kqemu_update_cpuid(CPUState *env)
{
- int critical_features_mask, features;
+ int critical_features_mask, features, ext_features, ext_features_mask;
uint32_t eax, ebx, ecx, edx;
/* the following features are kept identical on the host and
CPUID_CMOV | CPUID_CX8 |
CPUID_FXSR | CPUID_MMX | CPUID_SSE |
CPUID_SSE2 | CPUID_SEP;
+ ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR;
if (!is_cpuid_supported()) {
features = 0;
+ ext_features = 0;
} else {
cpuid(1, eax, ebx, ecx, edx);
features = edx;
+ ext_features = ecx;
}
#ifdef __x86_64__
/* NOTE: on x86_64 CPUs, SYSENTER is not supported in
#endif
env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
(features & critical_features_mask);
+ env->cpuid_ext_features = (env->cpuid_ext_features & ~ext_features_mask) |
+ (ext_features & ext_features_mask);
/* XXX: we could update more of the target CPUID state so that the
non accelerated code sees exactly the same CPU features as the
accelerated code */
perror("/tmp/kqemu.stats");
exit(1);
}
- fprintf(f, "total: %lld\n", total);
+ fprintf(f, "total: %" PRId64 "\n", total);
sum = 0;
for(i = 0; i < nb_pc_records; i++) {
r = pr[i];
sum += r->count;
- fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n",
+ fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n",
r->pc,
r->count,
(double)r->count / (double)total * 100.0,
int fd, data_order, must_swab, ret;
uint8_t e_ident[EI_NIDENT];
- fd = open(filename, O_RDONLY);
+ fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
perror(filename);
return -1;
c = *str++;
if (c == '\0')
break;
+ if (c == '\n')
+ term_outbuf[term_outbuf_index++] = '\r';
term_outbuf[term_outbuf_index++] = c;
- if (term_outbuf_index >= sizeof(term_outbuf) ||
+ if (term_outbuf_index >= (sizeof(term_outbuf) - 1) ||
c == '\n')
term_flush();
}
term_printf(" ");
switch(format) {
case 'o':
- term_printf("%#*llo", max_digits, v);
+ term_printf("%#*" PRIo64, max_digits, v);
break;
case 'x':
- term_printf("0x%0*llx", max_digits, v);
+ term_printf("0x%0*" PRIx64, max_digits, v);
break;
case 'u':
- term_printf("%*llu", max_digits, v);
+ term_printf("%*" PRIu64, max_digits, v);
break;
case 'd':
- term_printf("%*lld", max_digits, v);
+ term_printf("%*" PRId64, max_digits, v);
break;
case 'c':
term_printc(v);
#else
switch(format) {
case 'o':
- term_printf("%#llo", val);
+ term_printf("%#" PRIo64, val);
break;
case 'x':
- term_printf("%#llx", val);
+ term_printf("%#" PRIx64, val);
break;
case 'u':
- term_printf("%llu", val);
+ term_printf("%" PRIu64, val);
break;
default:
case 'd':
- term_printf("%lld", val);
+ term_printf("%" PRId64, val);
break;
case 'c':
term_printc(val);
{ 0x09, "8" },
{ 0x0a, "9" },
{ 0x0b, "0" },
+ { 0x0c, "minus" },
+ { 0x0d, "equal" },
{ 0x0e, "backspace" },
{ 0x0f, "tab" },
{ 0x45, "num_lock" },
{ 0x46, "scroll_lock" },
+ { 0xb5, "kp_divide" },
+ { 0x37, "kp_multiply" },
+ { 0x4a, "kp_substract" },
+ { 0x4e, "kp_add" },
+ { 0x9c, "kp_enter" },
+ { 0x53, "kp_decimal" },
+
+ { 0x52, "kp_0" },
+ { 0x4f, "kp_1" },
+ { 0x50, "kp_2" },
+ { 0x51, "kp_3" },
+ { 0x4b, "kp_4" },
+ { 0x4c, "kp_5" },
+ { 0x4d, "kp_6" },
+ { 0x47, "kp_7" },
+ { 0x48, "kp_8" },
+ { 0x49, "kp_9" },
+
{ 0x56, "<" },
{ 0x57, "f11" },
static int get_keycode(const char *key)
{
const KeyDef *p;
+ char *endp;
+ int ret;
for(p = key_defs; p->name != NULL; p++) {
if (!strcmp(key, p->name))
return p->keycode;
}
+ if (strstart(key, "0x", NULL)) {
+ ret = strtoul(key, &endp, 0);
+ if (*endp == '\0' && ret >= 0x01 && ret <= 0xff)
+ return ret;
+ }
return -1;
}
}
}
+static int mouse_button_state;
+
+static void do_mouse_move(const char *dx_str, const char *dy_str,
+ const char *dz_str)
+{
+ int dx, dy, dz;
+ dx = strtol(dx_str, NULL, 0);
+ dy = strtol(dy_str, NULL, 0);
+ dz = 0;
+ if (dz_str)
+ dz = strtol(dz_str, NULL, 0);
+ kbd_mouse_event(dx, dy, dz, mouse_button_state);
+}
+
+static void do_mouse_button(int button_state)
+{
+ mouse_button_state = button_state;
+ kbd_mouse_event(0, 0, 0, mouse_button_state);
+}
+
#ifndef CONFIG_DM
static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index)
{
}
}
#endif
-#endif /* !CONFIG_DM */
static void do_info_kqemu(void)
{
term_printf("kqemu support: not compiled\n");
#endif
}
+#endif /* !CONFIG_DM */
#ifdef CONFIG_PROFILER
total = qemu_time;
if (total == 0)
total = 1;
- term_printf("async time %lld (%0.3f)\n",
+ term_printf("async time %" PRId64 " (%0.3f)\n",
dev_time, dev_time / (double)ticks_per_sec);
- term_printf("qemu time %lld (%0.3f)\n",
+ term_printf("qemu time %" PRId64 " (%0.3f)\n",
qemu_time, qemu_time / (double)ticks_per_sec);
- term_printf("kqemu time %lld (%0.3f %0.1f%%) count=%lld int=%lld excp=%lld intr=%lld\n",
+ term_printf("kqemu time %" PRId64 " (%0.3f %0.1f%%) count=%" PRId64 " int=%" PRId64 " excp=%" PRId64 " intr=%" PRId64 "\n",
kqemu_time, kqemu_time / (double)ticks_per_sec,
kqemu_time / (double)total * 100.0,
kqemu_exec_count,
}
#endif
+/* Capture support */
+static LIST_HEAD (capture_list_head, CaptureState) capture_head;
+
+static void do_info_capture (void)
+{
+ int i;
+ CaptureState *s;
+
+ for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
+ term_printf ("[%d]: ", i);
+ s->ops.info (s->opaque);
+ }
+}
+
+static void do_stop_capture (int n)
+{
+ int i;
+ CaptureState *s;
+
+ for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
+ if (i == n) {
+ s->ops.destroy (s->opaque);
+ LIST_REMOVE (s, entries);
+ qemu_free (s);
+ return;
+ }
+ }
+}
+
+#ifdef HAS_AUDIO
+int wav_start_capture (CaptureState *s, const char *path, int freq,
+ int bits, int nchannels);
+
+static void do_wav_capture (const char *path,
+ int has_freq, int freq,
+ int has_bits, int bits,
+ int has_channels, int nchannels)
+{
+ CaptureState *s;
+
+ s = qemu_mallocz (sizeof (*s));
+ if (!s) {
+ term_printf ("Not enough memory to add wave capture\n");
+ return;
+ }
+
+ freq = has_freq ? freq : 44100;
+ bits = has_bits ? bits : 16;
+ nchannels = has_channels ? nchannels : 2;
+
+ if (wav_start_capture (s, path, freq, bits, nchannels)) {
+ term_printf ("Faied to add wave capture\n");
+ qemu_free (s);
+ }
+ LIST_INSERT_HEAD (&capture_head, s, entries);
+}
+#endif
+
static term_cmd_t term_cmds[] = {
{ "help|?", "s?", do_help,
"[cmd]", "show the help" },
{ "cpu", "i", do_cpu_set,
"index", "set the default CPU" },
#endif /* !CONFIG_DM */
+ { "mouse_move", "sss?", do_mouse_move,
+ "dx dy [dz]", "send mouse move events" },
+ { "mouse_button", "i", do_mouse_button,
+ "state", "change mouse button state (1=L, 2=M, 4=R)" },
+#ifdef HAS_AUDIO
+ { "wavcapture", "si?i?i?", do_wav_capture,
+ "path [frequency bits channels]",
+ "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
+#endif
+ { "stopcapture", "i", do_stop_capture,
+ "capture index", "stop capture" },
{ NULL, NULL, },
};
#endif
{ "jit", "", do_info_jit,
"", "show dynamic compiler info", },
-#endif /* !CONFIG_DM */
{ "kqemu", "", do_info_kqemu,
"", "show kqemu information", },
+#endif /* !CONFIG_DM */
{ "usb", "", usb_info,
"", "show guest USB devices", },
{ "usbhost", "", usb_host_info,
"", "show host USB devices", },
{ "profile", "", do_info_profile,
"", "show profiling information", },
+ { "capture", "", do_info_capture,
+ "show capture information" },
#ifdef CONFIG_DM
{ "hvmiopage", "", sp_info,
"", "show HVM device model shared page info", },
n = 0;
break;
default:
- /* XXX: 64 bit version */
+#if TARGET_LONG_BITS == 64
+ n = strtoull(pch, &p, 0);
+#else
n = strtoul(pch, &p, 0);
+#endif
if (pch == p) {
expr_error("invalid char in expression");
}
while (isspace(*p))
p++;
if (*typestr == '?' || *typestr == '.') {
- typestr++;
if (*typestr == '?') {
if (*p == '\0')
has_arg = 0;
has_arg = 0;
}
}
+ typestr++;
if (nb_args >= MAX_ARGS)
goto error_args;
args[nb_args++] = (void *)has_arg;
case 6:
cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
break;
+ case 7:
+ cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+ break;
default:
term_printf("unsupported number of arguments: %d\n", nb_args);
goto fail;
int nb_args, i, len;
const char *ptype, *str;
term_cmd_t *cmd;
+ const KeyDef *key;
parse_cmdline(cmdline, &nb_args, args);
#ifdef DEBUG_COMPLETION
for(cmd = info_cmds; cmd->name != NULL; cmd++) {
cmd_completion(str, cmd->name);
}
+ } else if (!strcmp(cmd->name, "sendkey")) {
+ completion_index = strlen(str);
+ for(key = key_defs; key->name != NULL; key++) {
+ cmd_completion(str, key->name);
+ }
}
break;
default:
#include <unistd.h>
#include "cpu.h"
+#if defined(USE_KQEMU)
+#include "vl.h"
+#endif
#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
VirtualFree(ptr, 0, MEM_RELEASE);
}
-#elif defined(USE_KQEMU)
+#else
+
+#if defined(USE_KQEMU)
#include <sys/vfs.h>
#include <sys/mman.h>
#include <fcntl.h>
-void *qemu_vmalloc(size_t size)
+void *kqemu_vmalloc(size_t size)
{
static int phys_ram_fd = -1;
static int phys_ram_size = 0;
"QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
"temporary RAM file will be opened.\n");
}
+ fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
exit(1);
}
}
return ptr;
}
-void qemu_vfree(void *ptr)
+void kqemu_vfree(void *ptr)
{
/* may be useful some day, but currently we do not need to free */
}
-#else
+#endif
/* alloc shared memory pages */
void *qemu_vmalloc(size_t size)
{
+#if defined(USE_KQEMU)
+ if (kqemu_allowed)
+ return kqemu_vmalloc(size);
+#endif
#ifdef _BSD
return valloc(size);
#else
void qemu_vfree(void *ptr)
{
+#if defined(USE_KQEMU)
+ if (kqemu_allowed)
+ kqemu_vfree(ptr);
+#endif
free(ptr);
}
#include <signal.h>
+struct siginfo;
+
/* NOTE: it works only because the glibc sigset_t is >= kernel sigset_t */
struct qemu_sigaction {
union {
- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
-- Proll is a GPL'd boot PROM for Sparc JavaStations
- (http://people.redhat.com/zaitcev/linux/).
- Applying proll.patch allows circumventing some bugs and enables
- faster kernel load through a hack.
-
- video.x is a PowerMac NDRV compatible driver for a VGA frame
buffer. It comes from the Mac-on-Linux project
(http://www.maconlinux.org/).
+
+- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
+ firmware implementation. The goal is to implement a 100% IEEE
+ 1275-1994 (referred to as Open Firmware) compliant firmware.
retrieving revision 1.4
diff -u -w -r1.4 apmbios.S
--- apmbios.S 26 Dec 2005 10:35:51 -0000 1.4
-+++ apmbios.S 28 Apr 2006 22:41:19 -0000
++++ apmbios.S 3 May 2006 21:22:46 -0000
@@ -225,6 +225,7 @@
APMSYM(05):
cmp al, #0x05
retrieving revision 1.160
diff -u -w -r1.160 rombios.c
--- rombios.c 25 Jan 2006 17:51:49 -0000 1.160
-+++ rombios.c 28 Apr 2006 22:41:21 -0000
++++ rombios.c 3 May 2006 21:22:48 -0000
@@ -1816,6 +1816,7 @@
{
printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
}
//--------------------------------------------------------------------------
-@@ -8713,6 +8717,7 @@
+@@ -3999,6 +4003,29 @@
+ }
+ #endif
+
++
++void set_e820_range(ES, DI, start, end, type)
++ Bit16u ES;
++ Bit16u DI;
++ Bit32u start;
++ Bit32u end;
++ Bit16u type;
++{
++ write_word(ES, DI, start);
++ write_word(ES, DI+2, start >> 16);
++ write_word(ES, DI+4, 0x00);
++ write_word(ES, DI+6, 0x00);
++
++ end -= start;
++ write_word(ES, DI+8, end);
++ write_word(ES, DI+10, end >> 16);
++ write_word(ES, DI+12, 0x0000);
++ write_word(ES, DI+14, 0x0000);
++
++ write_word(ES, DI+16, type);
++ write_word(ES, DI+18, 0x0);
++}
++
+ void
+ int15_function32(regs, ES, DS, FLAGS)
+ pushad_regs_t regs; // REGS pushed via pushad
+@@ -4063,19 +4090,8 @@
+ switch(regs.u.r16.bx)
+ {
+ case 0:
+- write_word(ES, regs.u.r16.di, 0x00);
+- write_word(ES, regs.u.r16.di+2, 0x00);
+- write_word(ES, regs.u.r16.di+4, 0x00);
+- write_word(ES, regs.u.r16.di+6, 0x00);
+-
+- write_word(ES, regs.u.r16.di+8, 0xFC00);
+- write_word(ES, regs.u.r16.di+10, 0x0009);
+- write_word(ES, regs.u.r16.di+12, 0x0000);
+- write_word(ES, regs.u.r16.di+14, 0x0000);
+-
+- write_word(ES, regs.u.r16.di+16, 0x1);
+- write_word(ES, regs.u.r16.di+18, 0x0);
+-
++ set_e820_range(ES, regs.u.r16.di,
++ 0x0000000L, 0x0009fc00L, 1);
+ regs.u.r32.ebx = 1;
+ regs.u.r32.eax = 0x534D4150;
+ regs.u.r32.ecx = 0x14;
+@@ -4083,6 +4099,24 @@
+ return;
+ break;
+ case 1:
++ set_e820_range(ES, regs.u.r16.di,
++ 0x0009fc00L, 0x000a0000L, 2);
++ regs.u.r32.ebx = 2;
++ regs.u.r32.eax = 0x534D4150;
++ regs.u.r32.ecx = 0x14;
++ CLEAR_CF();
++ return;
++ break;
++ case 2:
++ set_e820_range(ES, regs.u.r16.di,
++ 0x000e8000L, 0x00100000L, 2);
++ regs.u.r32.ebx = 3;
++ regs.u.r32.eax = 0x534D4150;
++ regs.u.r32.ecx = 0x14;
++ CLEAR_CF();
++ return;
++ break;
++ case 3:
+ extended_memory_size = inb_cmos(0x35);
+ extended_memory_size <<= 8;
+ extended_memory_size |= inb_cmos(0x34);
+@@ -4092,9 +4126,9 @@
+ extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
+ }
+ extended_memory_size *= 1024;
+- extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
++ extended_memory_size += (16L * 1024 * 1024);
+
+- if(extended_memory_size <= 15728640)
++ if(extended_memory_size <= (16L * 1024 * 1024))
+ {
+ extended_memory_size = inb_cmos(0x31);
+ extended_memory_size <<= 8;
+@@ -4102,28 +4136,23 @@
+ extended_memory_size *= 1024;
+ }
+
+- write_word(ES, regs.u.r16.di, 0x0000);
+- write_word(ES, regs.u.r16.di+2, 0x0010);
+- write_word(ES, regs.u.r16.di+4, 0x0000);
+- write_word(ES, regs.u.r16.di+6, 0x0000);
+-
+- write_word(ES, regs.u.r16.di+8, extended_memory_size);
+- extended_memory_size >>= 16;
+- write_word(ES, regs.u.r16.di+10, extended_memory_size);
+- extended_memory_size >>= 16;
+- write_word(ES, regs.u.r16.di+12, extended_memory_size);
+- extended_memory_size >>= 16;
+- write_word(ES, regs.u.r16.di+14, extended_memory_size);
+-
+- write_word(ES, regs.u.r16.di+16, 0x1);
+- write_word(ES, regs.u.r16.di+18, 0x0);
+-
+- regs.u.r32.ebx = 0;
++ set_e820_range(ES, regs.u.r16.di,
++ 0x00100000L, extended_memory_size, 1);
++ regs.u.r32.ebx = 4;
+ regs.u.r32.eax = 0x534D4150;
+ regs.u.r32.ecx = 0x14;
+ CLEAR_CF();
+ return;
+ break;
++ case 4:
++ /* 256KB BIOS area at the end of 4 GB */
++ set_e820_range(ES, regs.u.r16.di,
++ 0xfffc0000L, 0x00000000L, 2);
++ regs.u.r32.ebx = 0;
++ regs.u.r32.eax = 0x534D4150;
++ regs.u.r32.ecx = 0x14;
++ CLEAR_CF();
++ return;
+ default: /* AX=E820, DX=534D4150, BX unrecognized */
+ goto int15_unimplemented;
+ break;
+@@ -8713,6 +8742,7 @@
mov al, #0x80
bios32_end:
popf
retf
.align 16
-@@ -8823,17 +8828,17 @@
+@@ -8823,17 +8853,17 @@
pci_pro_fail:
pop edi
pop esi
retf
pci_pro_select_reg:
-@@ -8971,7 +8976,7 @@
+@@ -8971,7 +9001,7 @@
jmp pci_real_ok
pci_real_f0d: ;; write configuration dword
cmp al, #0x0d
call pci_real_select_reg
push dx
mov dx, #0x0cfc
-@@ -8979,6 +8984,46 @@
+@@ -8979,6 +9009,46 @@
out dx, eax
pop dx
jmp pci_real_ok
pci_real_unknown:
mov ah, #0x81
pci_real_fail:
-@@ -9019,6 +9064,7 @@
+@@ -9019,6 +9089,7 @@
dw 0,0 ;; Miniport data
db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
db 0x07 ;; checksum
;; first slot entry PCI-to-ISA (embedded)
db 0 ;; pci bus number
db 0x08 ;; pci device number (bit 7-3)
-@@ -9097,6 +9143,7 @@
+@@ -9097,6 +9168,7 @@
dw 0xdef8 ;; IRQ bitmap INTD#
db 5 ;; physical slot (0 = embedded)
db 0 ;; reserved
retrieving revision 1.17
diff -u -w -r1.17 Makefile
--- Makefile 6 Mar 2005 13:06:47 -0000 1.17
-+++ Makefile 25 Mar 2006 01:19:02 -0000
-@@ -17,9 +17,9 @@
- all: bios cirrus-bios
++++ Makefile 14 Jun 2006 00:51:06 -0000
+@@ -22,7 +22,7 @@
+ cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin
+ clean:
+- /bin/rm -f biossums *.o *.s *.ld86 \
++ /bin/rm -f biossums vbetables-gen vbetables.h *.o *.s *.ld86 \
+ temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak
--bios: biossums vgabios.bin vgabios.debug.bin
-+bios: biossums vgabios.bin #vgabios.debug.bin
-
--cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin
-+cirrus-bios: vgabios-cirrus.bin #vgabios-cirrus.debug.bin
+ dist-clean: clean
+@@ -79,3 +79,9 @@
- clean:
- /bin/rm -f biossums *.o *.s *.ld86 \
+ biossums: biossums.c
+ $(CC) -o biossums biossums.c
++
++vbetables-gen: vbetables-gen.c
++ $(CC) -o vbetables-gen vbetables-gen.c
++
++vbetables.h: vbetables-gen
++ ./vbetables-gen > $@
Index: clext.c
===================================================================
RCS file: /sources/vgabios/vgabios/clext.c,v
-retrieving revision 1.9
-diff -u -w -r1.9 clext.c
---- clext.c 4 Dec 2004 15:26:17 -0000 1.9
-+++ clext.c 25 Mar 2006 01:19:03 -0000
-@@ -238,6 +238,21 @@
- 0xffff
- };
-
-+/* 1600x1200x8 */
-+unsigned short cseq_1600x1200x8[] = {
-+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
-+0x760b,0x760c,0x760d,0x760e,
-+0x0412,0x0013,0x2017,
-+0x341b,0x341c,0x341d,0x341e,
-+0xffff
-+};
-+unsigned short ccrtc_1600x1200x8[] = {
-+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
-+0x6009,0x000c,0x000d,
-+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
-+0x001a,0x221b,0x001d,
-+0xffff
-+};
+retrieving revision 1.10
+diff -u -w -r1.10 clext.c
+--- clext.c 25 Mar 2006 10:19:15 -0000 1.10
++++ clext.c 14 Jun 2006 00:51:06 -0000
+@@ -544,6 +544,13 @@
+ cirrus_set_video_mode_extended:
+ call cirrus_switch_mode
+ pop ax ;; mode
++ test al, #0x80
++ jnz cirrus_set_video_mode_extended_1
++ push ax
++ mov ax, #0xffff ; set to 0xff to keep win 2K happy
++ call cirrus_clear_vram
++ pop ax
++cirrus_set_video_mode_extended_1:
+ and al, #0x7f
- cirrus_mode_t cirrus_modes[] =
- {
-@@ -291,6 +306,10 @@
- cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
- 6,5,11,6,5,5,0,0,0},
+ push ds
+@@ -1011,6 +1018,13 @@
+ jnz cirrus_vesa_02h_3
+ call cirrus_enable_16k_granularity
+ cirrus_vesa_02h_3:
++ test bx, #0x8000 ;; no clear
++ jnz cirrus_vesa_02h_4
++ push ax
++ xor ax,ax
++ call cirrus_clear_vram
++ pop ax
++cirrus_vesa_02h_4:
+ pop ax
+ push ds
+ #ifdef CIRRUS_VESA3_PMINFO
+@@ -1479,6 +1493,38 @@
+ pop bx
+ ret
-+ {0x7b,1600,1200,8,0x00,
-+ cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
-+ 4,0,0,0,0,0,0,0,0},
++cirrus_clear_vram:
++ pusha
++ push es
++ mov si, ax
+
- {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
- 0xff,0,0,0,0,0,0,0,0},
- {0xff,0,0,0,0,0,0,0,0,
-Index: vgabios.c
++ call cirrus_enable_16k_granularity
++ call cirrus_extbios_85h
++ shl al, #2
++ mov bl, al
++ xor ah,ah
++cirrus_clear_vram_1:
++ mov al, #0x09
++ mov dx, #0x3ce
++ out dx, ax
++ push ax
++ mov cx, #0xa000
++ mov es, cx
++ xor di, di
++ mov ax, si
++ mov cx, #8192
++ cld
++ rep
++ stosw
++ pop ax
++ inc ah
++ cmp ah, bl
++ jne cirrus_clear_vram_1
++
++ pop es
++ popa
++ ret
++
+ cirrus_extbios_handlers:
+ ;; 80h
+ dw cirrus_extbios_80h
+Index: vbe.c
===================================================================
-RCS file: /sources/vgabios/vgabios/vgabios.c,v
-retrieving revision 1.63
-diff -u -w -r1.63 vgabios.c
---- vgabios.c 26 Dec 2005 19:50:26 -0000 1.63
-+++ vgabios.c 25 Mar 2006 01:19:03 -0000
-@@ -111,6 +111,7 @@
- static void biosfn_read_video_state_size();
- static void biosfn_save_video_state();
- static void biosfn_restore_video_state();
-+extern Bit8u video_save_pointer_table[];
+RCS file: /sources/vgabios/vgabios/vbe.c,v
+retrieving revision 1.48
+diff -u -w -r1.48 vbe.c
+--- vbe.c 26 Dec 2005 19:50:26 -0000 1.48
++++ vbe.c 14 Jun 2006 00:51:07 -0000
+@@ -118,21 +118,114 @@
+ .word VBE_VESA_MODE_END_OF_LIST
+ #endif
- // This is for compiling with gcc2 and gcc3
- #define ASM_START #asm
-@@ -459,6 +460,29 @@
++ .align 2
+ vesa_pm_start:
+ dw vesa_pm_set_window - vesa_pm_start
+- dw vesa_pm_set_display_strt - vesa_pm_start
++ dw vesa_pm_set_display_start - vesa_pm_start
+ dw vesa_pm_unimplemented - vesa_pm_start
+- dw 0
++ dw vesa_pm_io_ports_table - vesa_pm_start
++vesa_pm_io_ports_table:
++ dw VBE_DISPI_IOPORT_INDEX
++ dw VBE_DISPI_IOPORT_INDEX + 1
++ dw VBE_DISPI_IOPORT_DATA
++ dw VBE_DISPI_IOPORT_DATA + 1
++ dw 0xffff
++ dw 0xffff
- pop ds
+ USE32
+ vesa_pm_set_window:
+- mov ax, #0x4f05
+- int #0x10
++ cmp bx, #0x00
++ je vesa_pm_set_display_window1
++ mov ax, #0x0100
++ ret
++vesa_pm_set_display_window1:
++ mov ax, dx
++ push dx
++ push ax
++ mov dx, # VBE_DISPI_IOPORT_INDEX
++ mov ax, # VBE_DISPI_INDEX_BANK
++ out dx, ax
++ pop ax
++ mov dx, # VBE_DISPI_IOPORT_DATA
++ out dx, ax
++ pop dx
++ mov ax, #0x004f
ret
+
+ vesa_pm_set_display_start:
+- mov ax, #0x4f07
+- int #0x10
++ cmp bl, #0x80
++ je vesa_pm_set_display_start1
++ cmp bl, #0x00
++ je vesa_pm_set_display_start1
++ mov ax, #0x0100
++ ret
++vesa_pm_set_display_start1:
++; convert offset to (X, Y) coordinate
++; (would be simpler to change Bochs VBE API...)
++ push eax
++ push ecx
++ push edx
++ push esi
++ push edi
++ shl edx, #16
++ and ecx, #0xffff
++ or ecx, edx
++ shl ecx, #2
++ mov eax, ecx
+
-+_video_save_pointer_table:
-+ .word _video_param_table
-+ .word 0xc000
-+
-+ .word 0 /* XXX: fill it */
-+ .word 0
-+
-+ .word 0 /* XXX: fill it */
-+ .word 0
++ push eax
++ mov dx, # VBE_DISPI_IOPORT_INDEX
++ mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH
++ out dx, ax
++ mov dx, # VBE_DISPI_IOPORT_DATA
++ in ax, dx
++ movzx ecx, ax
+
-+ .word 0 /* XXX: fill it */
-+ .word 0
++ mov dx, # VBE_DISPI_IOPORT_INDEX
++ mov ax, # VBE_DISPI_INDEX_BPP
++ out dx, ax
++ mov dx, # VBE_DISPI_IOPORT_DATA
++ in ax, dx
++ movzx esi, ax
++ pop eax
+
-+ .word 0 /* XXX: fill it */
-+ .word 0
++ add esi, #7
++ shr esi, #3
++ imul ecx, esi
++ xor edx, edx
++ div ecx
++ mov edi, eax
++ mov eax, edx
++ xor edx, edx
++ div esi
+
-+ .word 0 /* XXX: fill it */
-+ .word 0
++ push dx
++ push ax
++ mov dx, # VBE_DISPI_IOPORT_INDEX
++ mov ax, # VBE_DISPI_INDEX_X_OFFSET
++ out dx, ax
++ pop ax
++ mov dx, # VBE_DISPI_IOPORT_DATA
++ out dx, ax
++ pop dx
+
-+ .word 0 /* XXX: fill it */
-+ .word 0
++ mov ax, di
++ push dx
++ push ax
++ mov dx, # VBE_DISPI_IOPORT_INDEX
++ mov ax, # VBE_DISPI_INDEX_Y_OFFSET
++ out dx, ax
++ pop ax
++ mov dx, # VBE_DISPI_IOPORT_DATA
++ out dx, ax
++ pop dx
+
++ pop edi
++ pop esi
++ pop edx
++ pop ecx
++ pop eax
++ mov ax, #0x004f
+ ret
+
+ vesa_pm_unimplemented:
+@@ -835,6 +928,64 @@
ASM_END
- // --------------------------------------------------------------------------------------------
-@@ -780,8 +804,8 @@
- // Should we clear the screen ?
- Bit8u noclearmem=mode&0x80;
-- Bit8u line,mmask,*palette;
-- Bit16u i,twidth,theight,cheight;
-+ Bit8u line,mmask,*palette,vpti;
-+ Bit16u i,twidth,theightm1,cheight;
- Bit8u modeset_ctl,video_ctl,vga_switches;
- Bit16u crtc_addr;
-
-@@ -804,9 +828,10 @@
- if(line==0xFF)
- return;
++Bit16u vbe_biosfn_read_video_state_size()
++{
++ return 9 * 2;
++}
++
++void vbe_biosfn_save_video_state(ES, BX)
++ Bit16u ES; Bit16u BX;
++{
++ Bit16u enable, i;
++
++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
++ enable = inw(VBE_DISPI_IOPORT_DATA);
++ write_word(ES, BX, enable);
++ BX += 2;
++ if (!(enable & VBE_DISPI_ENABLED))
++ return;
++ for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
++ if (i != VBE_DISPI_INDEX_ENABLE) {
++ outw(VBE_DISPI_IOPORT_INDEX, i);
++ write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
++ BX += 2;
++ }
++ }
++}
++
++
++void vbe_biosfn_restore_video_state(ES, BX)
++ Bit16u ES; Bit16u BX;
++{
++ Bit16u enable, i;
++
++ enable = read_word(ES, BX);
++ BX += 2;
++
++ if (!(enable & VBE_DISPI_ENABLED)) {
++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
++ outw(VBE_DISPI_IOPORT_DATA, enable);
++ } else {
++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
++ BX += 2;
++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
++ BX += 2;
++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
++ BX += 2;
++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
++ outw(VBE_DISPI_IOPORT_DATA, enable);
++
++ for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
++ outw(VBE_DISPI_IOPORT_INDEX, i);
++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
++ BX += 2;
++ }
++ }
++}
++
+ /** Function 04h - Save/Restore State
+ *
+ * Input:
+@@ -849,10 +1000,48 @@
+ * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h)
+ *
+ */
+-void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX)
++void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX)
++Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX;
+ {
+-}
++ Bit16u ss=get_SS();
++ Bit16u result, val;
-- twidth=vga_modes[line].twidth;
-- theight=vga_modes[line].theight;
-- cheight=vga_modes[line].cheight;
-+ vpti=line_to_vpti[line];
-+ twidth=video_param_table[vpti].twidth;
-+ theightm1=video_param_table[vpti].theightm1;
-+ cheight=video_param_table[vpti].cheight;
-
- // Read the bios vga control
- video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
-@@ -866,21 +891,25 @@
- inb(VGAREG_ACTL_RESET);
++ result = 0x4f;
++ switch(GET_DL()) {
++ case 0x00:
++ val = biosfn_read_video_state_size2(CX);
++#ifdef DEBUG
++ printf("VGA state size=%x\n", val);
++#endif
++ if (CX & 8)
++ val += vbe_biosfn_read_video_state_size();
++ write_word(ss, BX, val);
++ break;
++ case 0x01:
++ val = read_word(ss, BX);
++ val = biosfn_save_video_state(CX, ES, val);
++#ifdef DEBUG
++ printf("VGA save_state offset=%x\n", val);
++#endif
++ if (CX & 8)
++ vbe_biosfn_save_video_state(ES, val);
++ break;
++ case 0x02:
++ val = read_word(ss, BX);
++ val = biosfn_restore_video_state(CX, ES, val);
++#ifdef DEBUG
++ printf("VGA restore_state offset=%x\n", val);
++#endif
++ if (CX & 8)
++ vbe_biosfn_restore_video_state(ES, val);
++ break;
++ default:
++ // function failed
++ result = 0x100;
++ break;
++ }
++ write_word(ss, AX, result);
++}
- // Set Attribute Ctl
-- for(i=0;i<=ACTL_MAX_REG;i++)
-+ for(i=0;i<=0x13;i++)
- {outb(VGAREG_ACTL_ADDRESS,i);
-- outb(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]);
-+ outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]);
- }
-+ outb(VGAREG_ACTL_ADDRESS,0x14);
-+ outb(VGAREG_ACTL_WRITE_DATA,0x00);
+ /** Function 05h - Display Window Control
+ *
+@@ -1090,7 +1279,7 @@
+ */
+ ASM_START
+ vbe_biosfn_return_protected_mode_interface:
+- test bx, bx
++ test bl, bl
+ jnz _fail
+ mov di, #0xc000
+ mov es, di
+Index: vbe.h
+===================================================================
+RCS file: /sources/vgabios/vgabios/vbe.h,v
+retrieving revision 1.24
+diff -u -w -r1.24 vbe.h
+--- vbe.h 9 May 2004 20:31:31 -0000 1.24
++++ vbe.h 14 Jun 2006 00:51:07 -0000
+@@ -14,7 +14,7 @@
+ void vbe_biosfn_return_controller_information(AX, ES, DI);
+ void vbe_biosfn_return_mode_information(AX, CX, ES, DI);
+ void vbe_biosfn_set_mode(AX, BX, ES, DI);
+-void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX);
++void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX);
+ void vbe_biosfn_set_get_palette_data(AX);
+ void vbe_biosfn_return_protected_mode_interface(AX);
- // Set Sequencer Ctl
-- for(i=0;i<=SEQU_MAX_REG;i++)
-+ outb(VGAREG_SEQU_ADDRESS,0);
-+ outb(VGAREG_SEQU_DATA,0x03);
-+ for(i=1;i<=4;i++)
- {outb(VGAREG_SEQU_ADDRESS,i);
-- outb(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]);
-+ outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]);
- }
+@@ -151,6 +151,12 @@
+ Bit8u Reserved[189];
+ } ModeInfoBlock;
- // Set Grafx Ctl
-- for(i=0;i<=GRDC_MAX_REG;i++)
-+ for(i=0;i<=8;i++)
- {outb(VGAREG_GRDC_ADDRESS,i);
-- outb(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]);
-+ outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]);
- }
++typedef struct ModeInfoListItem
++{
++ Bit16u mode;
++ ModeInfoBlockCompact info;
++} ModeInfoListItem;
++
+ // VBE Return Status Info
+ // AL
+ #define VBE_RETURN_STATUS_SUPPORTED 0x4F
+@@ -193,6 +199,10 @@
+ #define VBE_VESA_MODE_1280X1024X1555 0x119
+ #define VBE_VESA_MODE_1280X1024X565 0x11A
+ #define VBE_VESA_MODE_1280X1024X888 0x11B
++#define VBE_VESA_MODE_1600X1200X8 0x11C
++#define VBE_VESA_MODE_1600X1200X1555 0x11D
++#define VBE_VESA_MODE_1600X1200X565 0x11E
++#define VBE_VESA_MODE_1600X1200X888 0x11F
- // Set CRTC address VGA or MDA
-@@ -889,13 +918,13 @@
- // Disable CRTC write protection
- outw(crtc_addr,0x0011);
- // Set CRTC regs
-- for(i=0;i<=CRTC_MAX_REG;i++)
-+ for(i=0;i<=0x18;i++)
- {outb(crtc_addr,i);
-- outb(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]);
-+ outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]);
- }
+ // BOCHS/PLEX86 'own' mode numbers
+ #define VBE_OWN_MODE_320X200X8888 0x140
+@@ -202,6 +212,12 @@
+ #define VBE_OWN_MODE_1024X768X8888 0x144
+ #define VBE_OWN_MODE_1280X1024X8888 0x145
+ #define VBE_OWN_MODE_320X200X8 0x146
++#define VBE_OWN_MODE_1600X1200X8888 0x147
++#define VBE_OWN_MODE_1152X864X8 0x148
++#define VBE_OWN_MODE_1152X864X1555 0x149
++#define VBE_OWN_MODE_1152X864X565 0x14a
++#define VBE_OWN_MODE_1152X864X888 0x14b
++#define VBE_OWN_MODE_1152X864X8888 0x14c
- // Set the misc register
-- outb(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg);
-+ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg);
+ #define VBE_VESA_MODE_END_OF_LIST 0xFFFF
- // Enable video
- outb(VGAREG_ACTL_ADDRESS,0x20);
-@@ -927,9 +956,9 @@
- // Set the BIOS mem
- write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode);
- write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
-- write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength);
-+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l);
- write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
-- write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1);
-+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1);
- write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
- write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem));
- write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
-@@ -937,8 +966,8 @@
+@@ -259,7 +275,7 @@
+ // like 0xE0000000
- // FIXME We nearly have the good tables. to be reworked
- write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
-- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00);
-- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00);
-+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table);
-+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000);
- // FIXME
- write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
-@@ -1114,7 +1143,7 @@
- }
- else
- {
-- address = page*vga_modes[line].slength;
-+ address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l);
- }
+- #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4
++ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8
- // CRTC regs 0x0c and 0x0d
-@@ -1271,7 +1300,7 @@
- else
- {
- // FIXME gfx mode not complete
-- cheight=vga_modes[line].cheight;
-+ cheight=video_param_table[line_to_vpti[line]].cheight;
- switch(vga_modes[line].memmodel)
- {
- case PLANAR4:
-@@ -1581,7 +1610,7 @@
- else
- {
- // FIXME gfx mode not complete
-- cheight=vga_modes[line].cheight;
-+ cheight=video_param_table[line_to_vpti[line]].cheight;
- bpp=vga_modes[line].pixbits;
- while((count-->0) && (xcurs<nbcols))
- {
-@@ -1641,7 +1670,7 @@
- else
- {
- // FIXME gfx mode not complete
-- cheight=vga_modes[line].cheight;
-+ cheight=video_param_table[line_to_vpti[line]].cheight;
- bpp=vga_modes[line].pixbits;
- while((count-->0) && (xcurs<nbcols))
- {
-@@ -1949,7 +1978,7 @@
- else
- {
- // FIXME gfx mode not complete
-- cheight=vga_modes[line].cheight;
-+ cheight=video_param_table[line_to_vpti[line]].cheight;
- bpp=vga_modes[line].pixbits;
- switch(vga_modes[line].memmodel)
- {
-Index: vgatables.h
+ #define VBE_DISPI_BANK_ADDRESS 0xA0000
+ #define VBE_DISPI_BANK_SIZE_KB 64
+Index: vgabios.c
===================================================================
-RCS file: /sources/vgabios/vgabios/vgatables.h,v
-retrieving revision 1.9
-diff -u -w -r1.9 vgatables.h
---- vgatables.h 21 Sep 2005 18:45:20 -0000 1.9
-+++ vgatables.h 25 Mar 2006 01:19:04 -0000
-@@ -77,7 +77,7 @@
- * Tables of default values for each mode
- *
- */
--#define MODE_MAX 0x14
-+#define MODE_MAX 15
- #define TEXT 0x00
- #define GRAPH 0x01
-
-@@ -96,126 +96,38 @@
+RCS file: /sources/vgabios/vgabios/vgabios.c,v
+retrieving revision 1.64
+diff -u -w -r1.64 vgabios.c
+--- vgabios.c 25 Mar 2006 10:19:16 -0000 1.64
++++ vgabios.c 14 Jun 2006 00:51:07 -0000
+@@ -109,8 +109,8 @@
+ static void biosfn_write_string();
+ static void biosfn_read_state_info();
+ static void biosfn_read_video_state_size();
+-static void biosfn_save_video_state();
+-static void biosfn_restore_video_state();
++static Bit16u biosfn_save_video_state();
++static Bit16u biosfn_restore_video_state();
+ extern Bit8u video_save_pointer_table[];
- typedef struct
- {Bit8u svgamode;
-- Bit16u vesamode;
- Bit8u class; /* TEXT, GRAPH */
- Bit8u memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
-- Bit8u nbpages;
- Bit8u pixbits;
-- Bit16u swidth, sheight;
-- Bit16u twidth, theight;
-- Bit16u cwidth, cheight;
- Bit16u sstart;
-- Bit16u slength;
-- Bit8u miscreg;
- Bit8u pelmask;
-- Bit8u crtcmodel;
-- Bit8u actlmodel;
-- Bit8u grdcmodel;
-- Bit8u sequmodel;
- Bit8u dacmodel; /* 0 1 2 3 */
- } VGAMODES;
+ // This is for compiling with gcc2 and gcc3
+@@ -748,12 +748,7 @@
+ vbe_biosfn_set_mode(&AX,BX,ES,DI);
+ break;
+ case 0x04:
+- //FIXME
+-#ifdef DEBUG
+- unimplemented();
+-#endif
+- // function failed
+- AX=0x100;
++ vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+ break;
+ case 0x09:
+ //FIXME
+@@ -3138,23 +3133,215 @@
+ }
- static VGAMODES vga_modes[MODE_MAX+1]=
--{//mode vesa class model pg bits sw sh tw th cw ch sstart slength misc pelm crtc actl gdc sequ dac
-- {0x00, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02},
-- {0x01, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02},
-- {0x02, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02},
-- {0x03, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02},
-- {0x04, 0xFFFF, GRAPH, CGA, 4, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01},
-- {0x05, 0xFFFF, GRAPH, CGA, 1, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01},
-- {0x06, 0xFFFF, GRAPH, CGA, 1, 1, 640, 200, 80, 25, 8, 8, 0xB800, 0x1000, 0x63, 0xFF, 0x03, 0x02, 0x02, 0x03, 0x01},
-- {0x07, 0xFFFF, TEXT, MTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB000, 0x1000, 0x66, 0xFF, 0x04, 0x03, 0x03, 0x01, 0x00},
-- {0x0D, 0xFFFF, GRAPH, PLANAR4, 8, 4, 320, 200, 40, 25, 8, 8, 0xA000, 0x2000, 0x63, 0xFF, 0x05, 0x04, 0x04, 0x04, 0x01},
-- {0x0E, 0xFFFF, GRAPH, PLANAR4, 4, 4, 640, 200, 80, 25, 8, 8, 0xA000, 0x4000, 0x63, 0xFF, 0x06, 0x04, 0x04, 0x05, 0x01},
-- {0x0F, 0xFFFF, GRAPH, PLANAR1, 2, 1, 640, 350, 80, 25, 8, 14, 0xA000, 0x8000, 0xa3, 0xFF, 0x07, 0x05, 0x04, 0x05, 0x00},
-- {0x10, 0xFFFF, GRAPH, PLANAR4, 2, 4, 640, 350, 80, 25, 8, 14, 0xA000, 0x8000, 0xa3, 0xFF, 0x07, 0x06, 0x04, 0x05, 0x02},
-- {0x11, 0xFFFF, GRAPH, PLANAR1, 1, 1, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x07, 0x04, 0x05, 0x02},
-- {0x12, 0xFFFF, GRAPH, PLANAR4, 1, 4, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x06, 0x04, 0x05, 0x02},
-- {0x13, 0xFFFF, GRAPH, LINEAR8, 1, 8, 320, 200, 40, 25, 8, 8, 0xA000, 0x0000, 0x63, 0xFF, 0x09, 0x08, 0x05, 0x06, 0x03},
-- {0x6A, 0xFFFF, GRAPH, PLANAR4, 1, 4, 800, 600,100, 37, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x0A, 0x06, 0x04, 0x05, 0x02}
--};
--
--/* CRTC */
--#define CRTC_MAX_REG 0x18
--#define CRTC_MAX_MODEL 0x0A
--static Bit8u crtc_access[CRTC_MAX_REG+1]=
--{ /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
--};
--static Bit8u crtc_regs[CRTC_MAX_MODEL+1][CRTC_MAX_REG+1]=
--{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
-- /* 00 */ 0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,0xff,
-- /* 01 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff,
-- /* 02 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,0xff,
-- /* 03 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,0xff,
-- /* 04 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,0xff,
-- /* 05 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,0xff,
-- /* 06 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,0xff,
-- /* 07 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x85,0x5d,0x28,0x0f,0x63,0xba,0xe3,0xff,
-- /* 08 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x8c,0xdf,0x28,0x00,0xe7,0x04,0xe3,0xff,
-- /* 09 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,0xff,
-- /* 0A */ 0x7f,0x63,0x63,0x83,0x6b,0x1b,0x72,0xf0,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x8d,0x57,0x32,0x00,0x57,0x73,0xe3,0xff
--};
--
--/* Attribute Controler 0x3c0 */
--#define ACTL_MAX_REG 0x14
--#define ACTL_MAX_MODEL 0x08
--
--static Bit8u actl_access[ACTL_MAX_REG+1]=
--{/* 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
--};
--
--static Bit8u actl_regs[ACTL_MAX_MODEL+1][ACTL_MAX_REG+1]=
--{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */
-- /* 00 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x0c,0x00,0x0f,0x08,0x00,
-- /* 01 */ 0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x03,0x00,0x00,
-- /* 02 */ 0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x01,0x00,0x01,0x00,0x00,
-- /* 03 */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0e,0x00,0x0f,0x08,0x00,
-- /* 04 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x0f,0x00,0x00,
-- /* 05 */ 0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x01,0x00,0x01,0x00,0x00,
-- /* 06 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x01,0x00,0x0f,0x00,0x00,
-- /* 07 */ 0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x01,0x00,0x0f,0x00,0x00,
-- /* 08 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x41,0x00,0x0f,0x00,0x00
--};
--
--/* Sequencer 0x3c4 */
--#define SEQU_MAX_REG 0x04
--#define SEQU_MAX_MODEL 0x06
--
--static Bit8u sequ_access[SEQU_MAX_REG+1]=
--{ /* 00 01 02 03 04 */
-- 0x00,0x00,0x00,0x00,0x00
--};
--
--static Bit8u sequ_regs[SEQU_MAX_MODEL+1][SEQU_MAX_REG+1]=
--{/* Model 00 01 02 03 04 */
-- /* 00 */ 0x03,0x08,0x03,0x00,0x02,
-- /* 01 */ 0x03,0x00,0x03,0x00,0x02,
-- /* 02 */ 0x03,0x09,0x03,0x00,0x02,
-- /* 03 */ 0x03,0x01,0x01,0x00,0x06,
-- /* 04 */ 0x03,0x09,0x0f,0x00,0x06,
-- /* 05 */ 0x03,0x01,0x0f,0x00,0x06,
-- /* 06 */ 0x03,0x01,0x0f,0x00,0x0e
--};
--
--/* Graphic ctl 0x3ce */
--#define GRDC_MAX_REG 0x08
--#define GRDC_MAX_MODEL 0x05
--
--static Bit8u grdc_access[GRDC_MAX_REG+1]=
--{ /* 00 01 02 03 04 05 06 07 08 */
-- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
--};
--
--static Bit8u grdc_regs[GRDC_MAX_MODEL+1][GRDC_MAX_REG+1]=
--{/* Model 00 01 02 03 04 05 06 07 08 */
-- /* 00 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x0f,0xff,
-- /* 01 */ 0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x0f,0xff,
-- /* 02 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x0f,0xff,
-- /* 03 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x0f,0xff,
-- /* 04 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,0xff,
-- /* 05 */ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,0xff
-+{//mode class model bits sstart pelm dac
-+ {0x00, TEXT, CTEXT, 4, 0xB800, 0xFF, 0x02},
-+ {0x01, TEXT, CTEXT, 4, 0xB800, 0xFF, 0x02},
-+ {0x02, TEXT, CTEXT, 4, 0xB800, 0xFF, 0x02},
-+ {0x03, TEXT, CTEXT, 4, 0xB800, 0xFF, 0x02},
-+ {0x04, GRAPH, CGA, 2, 0xB800, 0xFF, 0x01},
-+ {0x05, GRAPH, CGA, 2, 0xB800, 0xFF, 0x01},
-+ {0x06, GRAPH, CGA, 1, 0xB800, 0xFF, 0x01},
-+ {0x07, TEXT, MTEXT, 4, 0xB000, 0xFF, 0x00},
-+ {0x0D, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x01},
-+ {0x0E, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x01},
-+ {0x0F, GRAPH, PLANAR1, 1, 0xA000, 0xFF, 0x00},
-+ {0x10, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02},
-+ {0x11, GRAPH, PLANAR1, 1, 0xA000, 0xFF, 0x02},
-+ {0x12, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02},
-+ {0x13, GRAPH, LINEAR8, 8, 0xA000, 0xFF, 0x03},
-+ {0x6A, GRAPH, PLANAR4, 4, 0xA000, 0xFF, 0x02}
-+};
+ // --------------------------------------------------------------------------------------------
+-static void biosfn_read_video_state_size (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
++// --------------------------------------------------------------------------------------------
++static Bit16u biosfn_read_video_state_size2 (CX)
++ Bit16u CX;
+ {
+-#ifdef DEBUG
+- unimplemented();
+-#endif
++ Bit16u size;
++ size = 0;
++ if (CX & 1) {
++ size += 0x46;
++ }
++ if (CX & 2) {
++ size += (5 + 8 + 5) * 2 + 6;
++ }
++ if (CX & 4) {
++ size += 3 + 256 * 3 + 1;
+ }
+-static void biosfn_save_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
++ return size;
++}
+
-+/* convert index in vga_modes[] to index in video_param_table[] */
-+static Bit8u line_to_vpti[MODE_MAX+1]={
-+ 0x17, 0x17, 0x18, 0x18, 0x04, 0x05, 0x06, 0x07,
-+ 0x0d, 0x0e, 0x11, 0x12, 0x1a, 0x1b, 0x1c, 0x1d,
- };
-
- /* Default Palette */
-@@ -224,6 +136,398 @@
- static Bit8u dac_regs[DAC_MAX_MODEL+1]=
- {0x3f,0x3f,0x3f,0xff};
++static void biosfn_read_video_state_size (CX, BX)
++ Bit16u CX; Bit16u *BX;
+ {
+-#ifdef DEBUG
+- unimplemented();
+-#endif
++ Bit16u ss=get_SS();
++ write_word(ss, BX, biosfn_read_video_state_size2(CX));
+ }
+-static void biosfn_restore_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
++
++static Bit16u biosfn_save_video_state (CX,ES,BX)
++ Bit16u CX;Bit16u ES;Bit16u BX;
+ {
+-#ifdef DEBUG
+- unimplemented();
+-#endif
++ Bit16u i, v, crtc_addr, ar_index;
++
++ crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
++ if (CX & 1) {
++ write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
++ write_byte(ES, BX, inb(crtc_addr)); BX++;
++ write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
++ inb(VGAREG_ACTL_RESET);
++ ar_index = inb(VGAREG_ACTL_ADDRESS);
++ write_byte(ES, BX, ar_index); BX++;
++ write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
++
++ for(i=1;i<=4;i++){
++ outb(VGAREG_SEQU_ADDRESS, i);
++ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
++ }
++ outb(VGAREG_SEQU_ADDRESS, 0);
++ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
++
++ for(i=0;i<=0x18;i++) {
++ outb(crtc_addr,i);
++ write_byte(ES, BX, inb(crtc_addr+1)); BX++;
++ }
++
++ for(i=0;i<=0x13;i++) {
++ inb(VGAREG_ACTL_RESET);
++ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
++ write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
++ }
++ inb(VGAREG_ACTL_RESET);
++
++ for(i=0;i<=8;i++) {
++ outb(VGAREG_GRDC_ADDRESS,i);
++ write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
++ }
++
++ write_word(ES, BX, crtc_addr); BX+= 2;
++
++ /* XXX: read plane latches */
++ write_byte(ES, BX, 0); BX++;
++ write_byte(ES, BX, 0); BX++;
++ write_byte(ES, BX, 0); BX++;
++ write_byte(ES, BX, 0); BX++;
++ }
++ if (CX & 2) {
++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
++ for(i=0;i<8;i++) {
++ write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
++ BX += 2;
++ }
++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
++ /* current font */
++ write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
++ write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
++ write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
++ write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
++ }
++ if (CX & 4) {
++ /* XXX: check this */
++ write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
++ write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
++ write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
++ // Set the whole dac always, from 0
++ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
++ for(i=0;i<256*3;i++) {
++ write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
++ }
++ write_byte(ES, BX, 0); BX++; /* color select register */
++ }
++ return BX;
++}
++
++static Bit16u biosfn_restore_video_state (CX,ES,BX)
++ Bit16u CX;Bit16u ES;Bit16u BX;
++{
++ Bit16u i, crtc_addr, v, addr1, ar_index;
++
++ if (CX & 1) {
++ // Reset Attribute Ctl flip-flop
++ inb(VGAREG_ACTL_RESET);
++
++ crtc_addr = read_word(ES, BX + 0x40);
++ addr1 = BX;
++ BX += 5;
++
++ for(i=1;i<=4;i++){
++ outb(VGAREG_SEQU_ADDRESS, i);
++ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
++ }
++ outb(VGAREG_SEQU_ADDRESS, 0);
++ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
++
++ // Disable CRTC write protection
++ outw(crtc_addr,0x0011);
++ // Set CRTC regs
++ for(i=0;i<=0x18;i++) {
++ if (i != 0x11) {
++ outb(crtc_addr,i);
++ outb(crtc_addr+1, read_byte(ES, BX));
++ }
++ BX++;
++ }
++ // select crtc base address
++ v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
++ if (crtc_addr = 0x3d4)
++ v |= 0x01;
++ outb(VGAREG_WRITE_MISC_OUTPUT, v);
++
++ // enable write protection if needed
++ outb(crtc_addr, 0x11);
++ outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
++
++ // Set Attribute Ctl
++ ar_index = read_byte(ES, addr1 + 0x03);
++ inb(VGAREG_ACTL_RESET);
++ for(i=0;i<=0x13;i++) {
++ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
++ outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
++ }
++ outb(VGAREG_ACTL_ADDRESS, ar_index);
++ inb(VGAREG_ACTL_RESET);
++
++ for(i=0;i<=8;i++) {
++ outb(VGAREG_GRDC_ADDRESS,i);
++ outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
++ }
++ BX += 2; /* crtc_addr */
++ BX += 4; /* plane latches */
++
++ outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
++ outb(crtc_addr, read_byte(ES, addr1)); addr1++;
++ outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
++ addr1++;
++ outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
++ }
++ if (CX & 2) {
++ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
++ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
++ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
++ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
++ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
++ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
++ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
++ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
++ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
++ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
++ for(i=0;i<8;i++) {
++ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
++ BX += 2;
++ }
++ write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
++ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
++ /* current font */
++ write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
++ write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
++ write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
++ write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
++ }
++ if (CX & 4) {
++ BX++;
++ v = read_byte(ES, BX); BX++;
++ outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
++ // Set the whole dac always, from 0
++ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
++ for(i=0;i<256*3;i++) {
++ outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
++ }
++ BX++;
++ outb(VGAREG_DAC_WRITE_ADDRESS, v);
++ }
++ return BX;
+ }
-+/* standard BIOS Video Parameter Table */
+ // ============================================================================================
+diff -u -w vbetables-gen.c
+--- vbetables-gen.c 1970-01-01 01:00:00.000000000 +0100
++++ vbetables-gen.c 2006-06-14 00:52:18.000000000 +0200
+@@ -0,0 +1,217 @@
++/* Generate the VGABIOS VBE Tables */
++#include <stdlib.h>
++#include <stdio.h>
++
+typedef struct {
-+ Bit8u twidth;
-+ Bit8u theightm1;
-+ Bit8u cheight;
-+ Bit8u slength_l;
-+ Bit8u slength_h;
-+ Bit8u sequ_regs[4];
-+ Bit8u miscreg;
-+ Bit8u crtc_regs[25];
-+ Bit8u actl_regs[20];
-+ Bit8u grdc_regs[9];
-+} VideoParamTableEntry;
-+
-+static VideoParamTableEntry video_param_table[30] = {
-+{
-+ /* index=0x00 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x01 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x02 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x03 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x04 vga mode 0x04 */
-+ 40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
-+ 0x09, 0x03, 0x00, 0x02, /* sequ_regs */
-+ 0x63, /* miscreg */
-+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
-+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
-+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-+ 0x01, 0x00, 0x03, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x05 vga mode 0x05 */
-+ 40, 24, 8, 0x00, 0x08, /* tw, th-1, ch, slength */
-+ 0x09, 0x03, 0x00, 0x02, /* sequ_regs */
-+ 0x63, /* miscreg */
-+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
-+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
-+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-+ 0x01, 0x00, 0x03, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x06 vga mode 0x06 */
-+ 80, 24, 8, 0x00, 0x10, /* tw, th-1, ch, slength */
-+ 0x01, 0x01, 0x00, 0x06, /* sequ_regs */
-+ 0x63, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
-+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
-+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
-+ 0x01, 0x00, 0x01, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x07 vga mode 0x07 */
-+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
-+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
-+ 0x66, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-+ 0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x08 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x09 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x0a no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x0b no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x0c no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x0d vga mode 0x0d */
-+ 40, 24, 8, 0x00, 0x20, /* tw, th-1, ch, slength */
-+ 0x09, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0x63, /* miscreg */
-+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
-+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x0e vga mode 0x0e */
-+ 80, 24, 8, 0x00, 0x40, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0x63, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
-+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x0f no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x10 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x11 vga mode 0x0f */
-+ 80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0xa3, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
-+ 0x01, 0x00, 0x01, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x12 vga mode 0x10 */
-+ 80, 24, 14, 0x00, 0x80, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0xa3, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x13 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x14 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x15 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x16 no mode defined */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+},
-+{
-+ /* index=0x17 vga mode 0x01 */
-+ 40, 24, 16, 0x00, 0x08, /* tw, th-1, ch, slength */
-+ 0x08, 0x03, 0x00, 0x02, /* sequ_regs */
-+ 0x67, /* miscreg */
-+ 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
-+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x18 vga mode 0x03 */
-+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
-+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
-+ 0x67, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x0c, 0x00, 0x0f, 0x08, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x19 vga mode 0x07 */
-+ 80, 24, 16, 0x00, 0x10, /* tw, th-1, ch, slength */
-+ 0x00, 0x03, 0x00, 0x02, /* sequ_regs */
-+ 0x66, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
-+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
-+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-+ 0x0e, 0x00, 0x0f, 0x08, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x1a vga mode 0x11 */
-+ 80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0xe3, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
-+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
-+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x1b vga mode 0x12 */
-+ 80, 29, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0xe3, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x1c vga mode 0x13 */
-+ 40, 24, 8, 0x00, 0x00, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x0e, /* sequ_regs */
-+ 0x63, /* miscreg */
-+ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
-+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-+ 0x41, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
-+{
-+ /* index=0x1d vga mode 0x6a */
-+ 100, 36, 16, 0x00, 0x00, /* tw, th-1, ch, slength */
-+ 0x01, 0x0f, 0x00, 0x06, /* sequ_regs */
-+ 0xe3, /* miscreg */
-+ 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
-+ 0xff, /* crtc_regs */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-+ 0x01, 0x00, 0x0f, 0x00, /* actl_regs */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* grdc_regs */
-+},
++ int width;
++ int height;
++ int depth;
++ int mode;
++} ModeInfo;
++
++ModeInfo modes[] = {
++ /* standard VESA modes */
++{ 640, 400, 8 , 0x100},
++{ 640, 480, 8 , 0x101},
++{ 800, 600, 4 , 0x102},
++{ 800, 600, 8 , 0x103},
++ //{ 1024, 768, 4 , 0x104},
++{ 1024, 768, 8 , 0x105},
++ //{ 1280, 1024, 4 , 0x106},
++{ 1280, 1024, 8 , 0x107},
++{ 320, 200, 15 , 0x10D},
++{ 320, 200, 16 , 0x10E},
++{ 320, 200, 24 , 0x10F},
++{ 640, 480, 15 , 0x110},
++{ 640, 480, 16 , 0x111},
++{ 640, 480, 24 , 0x112},
++{ 800, 600, 15 , 0x113},
++{ 800, 600, 16 , 0x114},
++{ 800, 600, 24 , 0x115},
++{ 1024, 768, 15 , 0x116},
++{ 1024, 768, 16 , 0x117},
++{ 1024, 768, 24 , 0x118},
++{ 1280, 1024, 15 , 0x119},
++{ 1280, 1024, 16 , 0x11A},
++{ 1280, 1024, 24 , 0x11B},
++{ 1600, 1200, 8 , 0x11C},
++{ 1600, 1200, 15 , 0x11D},
++{ 1600, 1200, 16 , 0x11E},
++{ 1600, 1200, 24 , 0x11F},
++
++ /* BOCHS/PLE, 86 'own' mode numbers */
++{ 320, 200, 32 , 0x140},
++{ 640, 400, 32 , 0x141},
++{ 640, 480, 32 , 0x142},
++{ 800, 600, 32 , 0x143},
++{ 1024, 768, 32 , 0x144},
++{ 1280, 1024, 32 , 0x145},
++{ 320, 200, 8 , 0x146},
++{ 1600, 1200, 32 , 0x147},
++{ 1152, 864, 8 , 0x148},
++{ 1152, 864, 15 , 0x149},
++{ 1152, 864, 16 , 0x14a},
++{ 1152, 864, 24 , 0x14b},
++{ 1152, 864, 32 , 0x14c},
++{ 0, },
+};
+
- /* Mono */
- static Bit8u palette0[63+1][3]=
- {
++int main(int argc, char **argv)
++{
++ const ModeInfo *pm;
++ int pitch, r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos;
++ const char *str;
++
++ printf("/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT */\n");
++ printf("static ModeInfoListItem mode_info_list[]=\n");
++ printf("{\n");
++ for(pm = modes; pm->mode != 0; pm++) {
++ printf("{ 0x%04x, /* %dx%dx%d */\n",
++ pm->mode, pm->width, pm->height, pm->depth);
++ printf("{ /*Bit16u ModeAttributes*/ %s,\n",
++ "VBE_MODE_ATTRIBUTE_SUPPORTED | "
++ "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | "
++ "VBE_MODE_ATTRIBUTE_COLOR_MODE | "
++ "VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | "
++ "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE");
++
++ printf("/*Bit8u WinAAttributes*/ %s,\n",
++ "VBE_WINDOW_ATTRIBUTE_RELOCATABLE | "
++ "VBE_WINDOW_ATTRIBUTE_READABLE | "
++ "VBE_WINDOW_ATTRIBUTE_WRITEABLE");
++
++ printf("/*Bit8u WinBAttributes*/ %d,\n", 0);
++
++ printf("/*Bit16u WinGranularity*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
++
++ printf("/*Bit16u WinSize*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
++
++ printf("/*Bit16u WinASegment*/ %s,\n", "VGAMEM_GRAPH");
++
++ printf("/*Bit16u WinBSegment*/ 0x%04x,\n", 0);
++
++ printf("/*Bit32u WinFuncPtr*/ %d,\n", 0);
++
++ if (pm->depth == 4)
++ pitch = (pm->width + 7) / 8;
++ else
++ pitch = pm->width * ((pm->depth + 7) / 8);
++ printf("/*Bit16u BytesPerScanLine*/ %d,\n", pitch);
++
++ // Mandatory information for VBE 1.2 and above
++ printf("/*Bit16u XResolution*/ %d,\n", pm->width);
++ printf("/*Bit16u YResolution*/ %d,\n", pm->height);
++ printf("/*Bit8u XCharSize*/ %d,\n", 8);
++ printf("/*Bit8u YCharSize*/ %d,\n", 16);
++ if (pm->depth == 4) {
++ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 4);
++ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth);
++ } else {
++ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 1);
++ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth);
++ }
++ printf("/*Bit8u NumberOfBanks*/ %d,\n",
++ (pm->height * pitch + 65535) / 65536);
++
++ if (pm->depth == 4)
++ str = "VBE_MEMORYMODEL_PLANAR";
++ else if (pm->depth == 8)
++ str = "VBE_MEMORYMODEL_PACKED_PIXEL";
++ else
++ str = "VBE_MEMORYMODEL_DIRECT_COLOR";
++ printf("/*Bit8u MemoryModel*/ %s,\n", str);
++ printf("/*Bit8u BankSize*/ %d,\n", 0);
++ /* XXX: check */
++ printf("/*Bit8u NumberOfImagePages*/ %d,\n", 0);
++ printf("/*Bit8u Reserved_page*/ %d,\n", 0);
++
++ // Direct Color fields (required for direct/6 and YUV/7 memory models)
++ switch(pm->depth) {
++ case 15:
++ r_size = 5;
++ r_pos = 10;
++ g_size = 5;
++ g_pos = 5;
++ b_size = 5;
++ b_pos = 0;
++ a_size = 1;
++ a_pos = 15;
++ break;
++ case 16:
++ r_size = 5;
++ r_pos = 11;
++ g_size = 6;
++ g_pos = 5;
++ b_size = 5;
++ b_pos = 0;
++ a_size = 0;
++ a_pos = 0;
++ break;
++ case 24:
++ r_size = 8;
++ r_pos = 16;
++ g_size = 8;
++ g_pos = 8;
++ b_size = 8;
++ b_pos = 0;
++ a_size = 0;
++ a_pos = 0;
++ break;
++ case 32:
++ r_size = 8;
++ r_pos = 16;
++ g_size = 8;
++ g_pos = 8;
++ b_size = 8;
++ b_pos = 0;
++ a_size = 8;
++ a_pos = 24;
++ break;
++ default:
++ r_size = 0;
++ r_pos = 0;
++ g_size = 0;
++ g_pos = 0;
++ b_size = 0;
++ b_pos = 0;
++ a_size = 0;
++ a_pos = 0;
++ break;
++ }
++
++ printf("/*Bit8u RedMaskSize*/ %d,\n", r_size);
++ printf("/*Bit8u RedFieldPosition*/ %d,\n", r_pos);
++ printf("/*Bit8u GreenMaskSize*/ %d,\n", g_size);
++ printf("/*Bit8u GreenFieldPosition*/ %d,\n", g_pos);
++ printf("/*Bit8u BlueMaskSize*/ %d,\n", b_size);
++ printf("/*Bit8u BlueFieldPosition*/ %d,\n", b_pos);
++ printf("/*Bit8u RsvdMaskSize*/ %d,\n", a_size);
++ printf("/*Bit8u RsvdFieldPosition*/ %d,\n", a_pos);
++ printf("/*Bit8u DirectColorModeInfo*/ %d,\n", 0);
++
++// Mandatory information for VBE 2.0 and above
++ printf("/*Bit32u PhysBasePtr*/ %s,\n",
++ "VBE_DISPI_LFB_PHYSICAL_ADDRESS");
++ printf("/*Bit32u OffScreenMemOffset*/ %d,\n", 0);
++ printf("/*Bit16u OffScreenMemSize*/ %d,\n", 0);
++ // Mandatory information for VBE 3.0 and above
++ printf("/*Bit16u LinBytesPerScanLine*/ %d,\n", pitch);
++ printf("/*Bit8u BnkNumberOfPages*/ %d,\n", 0);
++ printf("/*Bit8u LinNumberOfPages*/ %d,\n", 0);
++ printf("/*Bit8u LinRedMaskSize*/ %d,\n", r_size);
++ printf("/*Bit8u LinRedFieldPosition*/ %d,\n", r_pos);
++ printf("/*Bit8u LinGreenMaskSize*/ %d,\n", g_size);
++ printf("/*Bit8u LinGreenFieldPosition*/ %d,\n", g_pos);
++ printf("/*Bit8u LinBlueMaskSize*/ %d,\n", b_size);
++ printf("/*Bit8u LinBlueFieldPosition*/ %d,\n", b_pos);
++ printf("/*Bit8u LinRsvdMaskSize*/ %d,\n", a_size);
++ printf("/*Bit8u LinRsvdFieldPosition*/ %d,\n", a_pos);
++ printf("/*Bit32u MaxPixelClock*/ %d,\n", 0);
++ printf("} },\n");
++ }
++ printf("{ VBE_VESA_MODE_END_OF_LIST,\n");
++ printf("{ 0,\n");
++ printf("} },\n");
++ printf("};\n");
++ return 0;
++}
@item Sun4u (64-bit Sparc processor, in progress)
@item Malta board (32-bit MIPS processor)
@item ARM Integrator/CP (ARM926E or 1026E processor)
+@item ARM Versatile baseboard (ARM926E)
@end itemize
For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported.
the raw disk image you use is not written back. You can however force
the write back by pressing @key{C-a s} (@pxref{disk_images}).
+@item -no-fd-bootchk
+Disable boot signature checking for floppy disks in Bochs BIOS. It may
+be needed to boot from old floppy disks.
+
@item -m megs
Set virtual RAM size to @var{megs} megabytes. Default is 128 MB.
@item -vnc d
Normally, QEMU uses SDL to display the VGA output. With this option,
-you can have QEMU listen on VNC display d and redirect the VGA display
-over the VNC session. It is very useful to enable the usb tablet device
-when using this option (option @option{-usbdevice tablet}).
+you can have QEMU listen on VNC display @var{d} and redirect the VGA
+display over the VNC session. It is very useful to enable the usb
+tablet device when using this option (option @option{-usbdevice
+tablet}). When using the VNC display, you must use the @option{-k}
+option to set the keyboard layout.
@item -k language
Use keyboard layout @var{language} (for example @code{fr} for
French). This option is only needed where it is not easy to get raw PC
-keycodes (e.g. on Macs or with some X11 servers). You don't need to
-use it on PC/Linux or PC/Windows hosts.
+keycodes (e.g. on Macs, with some X11 servers or with a VNC
+display). You don't normally need to use it on PC/Linux or PC/Windows
+hosts.
The available layouts are:
@example
Enable the USB driver (will be the default soon)
@item -usbdevice devname
-Add the USB device @var{devname}. See the monitor command
-@code{usb_add} to have more information.
+Add the USB device @var{devname}. @xref{usb_devices}.
@end table
Network options:
@table @option
@item -serial dev
-Redirect the virtual serial port to host device @var{dev}. Available
-devices are:
+Redirect the virtual serial port to host character device
+@var{dev}. The default device is @code{vc} in graphical mode and
+@code{stdio} in non graphical mode.
+
+This option can be used several times to simulate up to 4 serials
+ports.
+
+Available character devices are:
@table @code
@item vc
Virtual console
@item stdio
[Unix only] standard input/output
@item pipe:filename
-[Unix only] name pipe @var{filename}
+name pipe @var{filename}
+@item COMn
+[Windows only] Use host serial port @var{n}
+@item udp:[remote_host]:remote_port[@@[src_ip]:src_port]
+This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specifed @var{src_port} a random port is automatically chosen.
+
+If you just want a simple readonly console you can use @code{netcat} or
+@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
+@code{nc -u -l -p 4555}. Any time qemu writes something to that port it
+will appear in the netconsole session.
+
+If you plan to send characters back via netconsole or you want to stop
+and start qemu a lot of times, you should have qemu use the same
+source port each time by using something like @code{-serial
+udp::4555@@:4556} to qemu. Another approach is to use a patched
+version of netcat which can listen to a TCP port and send and receive
+characters via udp. If you have a patched version of netcat which
+activates telnet remote echo and single char transfer, then you can
+use the following options to step up a netcat redirector to allow
+telnet on port 5555 to access the qemu port.
+@table @code
+@item Qemu Options:
+-serial udp::4555@@:4556
+@item netcat options:
+-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T
+@item telnet options:
+localhost 5555
@end table
-The default device is @code{vc} in graphical mode and @code{stdio} in
-non graphical mode.
-This option can be used several times to simulate up to 4 serials
-ports.
+
+@item tcp:[host]:port[,server][,nowait]
+The TCP Net Console has two modes of operation. It can send the serial
+I/O to a location or wait for a connection from a location. By default
+the TCP Net Console is sent to @var{host} at the @var{port}. If you use
+the @var{,server} option QEMU will wait for a client socket application
+to connect to the port before continuing, unless the @code{,nowait}
+option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only
+one TCP connection at a time is accepted. You can use @code{telnet} to
+connect to the corresponding character device.
+@table @code
+@item Example to send tcp console to 192.168.0.2 port 4444
+-serial tcp:192.168.0.2:4444
+@item Example to listen and wait on port 4444 for connection
+-serial tcp::4444,server
+@item Example to not wait and listen on ip 192.168.0.100 port 4444
+-serial tcp:192.168.0.100:4444,server,nowait
+@end table
+
+@item telnet:host:port[,server][,nowait]
+The telnet protocol is used instead of raw tcp sockets. The options
+work the same as if you had specified @code{-serial tcp}. The
+difference is that the port acts like a telnet server or client using
+telnet option negotiation. This will also allow you to send the
+MAGIC_SYSRQ sequence if you use a telnet that supports sending the break
+sequence. Typically in unix telnet you do it with Control-] and then
+type "send break" followed by pressing the enter key.
+
+@end table
@item -parallel dev
Redirect the virtual parallel port to host device @var{dev} (same
@item -std-vga
Simulate a standard VGA card with Bochs VBE extensions (default is
-Cirrus Logic GD5446 PCI VGA)
+Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0
+VBE extensions (e.g. Windows XP) and if you want to use high
+resolution modes (>= 1280x1024x16) then you should use this option.
+
+@item -no-acpi
+Disable ACPI (Advanced Configuration and Power Interface) support. Use
+it if your guest OS complains about ACPI problems (PC target machine
+only).
+
@item -loadvm file
Start right away with a saved state (@code{loadvm} in monitor)
@end table
show USB devices plugged on the virtual USB hub
@item info usbhost
show all USB host devices
+@item info capture
+show information about active capturing
@end table
@item q or quit
@item screendump filename
Save screen into PPM image @var{filename}.
+@item wavcapture filename [frequency [bits [channels]]]
+Capture audio into @var{filename}. Using sample rate @var{frequency}
+bits per sample @var{bits} and number of channels @var{channels}.
+
+Defaults:
+@itemize @minus
+@item Sample rate = 44100 Hz - CD quality
+@item Bits = 16
+@item Number of channels = 2 - Stereo
+@end itemize
+
+@item stopcapture index
+Stop capture with a given @var{index}, index can be obtained with
+@example
+info capture
+@end example
+
@item log item1[,...]
Activate logging of the specified items to @file{/tmp/qemu.log}.
@item usb_add devname
-Plug the USB device devname to the QEMU virtual USB hub. @var{devname}
-is either a virtual device name (for example @code{mouse}) or a host
-USB device identifier. Host USB device identifiers have the following
-syntax: @code{host:bus.addr} or @code{host:vendor_id:product_id}.
+Add the USB device @var{devname}. For details of available devices see
+@ref{usb_devices}
@item usb_del devname
@node pcsys_usb
@section USB emulation
-QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected
-to it. You can virtually plug to the hub virtual USB devices or real
-host USB devices (experimental, works only on Linux hosts).
-
-@subsection Using virtual USB devices
-
-A virtual USB mouse device is available for testing in QEMU.
-
-You can try it with the following monitor commands:
+QEMU emulates a PCI UHCI USB controller. You can virtually plug
+virtual USB devices or real host USB devices (experimental, works only
+on Linux hosts). Qemu will automatically create and connect virtual USB hubs
+as neccessary to connect multiple USB devices.
-@example
-# add the mouse device
-(qemu) usb_add mouse
+@menu
+* usb_devices::
+* host_usb_devices::
+@end menu
+@node usb_devices
+@subsection Connecting USB devices
-# show the virtual USB devices plugged on the QEMU Virtual USB hub
-(qemu) info usb
- Device 0.3, speed 12 Mb/s
+USB devices can be connected with the @option{-usbdevice} commandline option
+or the @code{usb_add} monitor command. Available devices are:
-# after some time you can try to remove the mouse
-(qemu) usb_del 0.3
-@end example
-
-The option @option{-usbdevice} is similar to the monitor command
-@code{usb_add}.
+@table @var
+@item @code{mouse}
+Virtual Mouse. This will override the PS/2 mouse emulation when activated.
+@item @code{tablet}
+Pointer device that uses abolsute coordinates (like a touchscreen).
+This means qemu is able to report the mouse position without having
+to grab the mouse. Also overrides the PS/2 mouse emulation when activated.
+@item @code{disk:file}
+Mass storage device based on @var{file} (@pxref{disk_images})
+@item @code{host:bus.addr}
+Pass through the host device identified by @var{bus.addr}
+(Linux only)
+@item @code{host:vendor_id:product_id}
+Pass through the host device identified by @var{vendor_id:product_id}
+(Linux only)
+@end table
+@node host_usb_devices
@subsection Using host USB devices on a Linux host
WARNING: this is an experimental feature. QEMU will slow down when
Use @code{x/10i $eip} to display the code at the PC position.
@item
Use @code{set architecture i8086} to dump 16 bit code. Then use
-@code{x/10i $cs*16+*eip} to dump the code at the PC position.
+@code{x/10i $cs*16+$eip} to dump the code at the PC position.
@end enumerate
@node pcsys_os_specific
and use this graphic card. For optimal performances, use 16 bit color
depth in the guest and the host OS.
+If you are using Windows XP as guest OS and if you want to use high
+resolution modes which the Cirrus Logic BIOS does not support (i.e. >=
+1280x1024x16), then you should use the VESA VBE virtual graphic card
+(option @option{-std-vga}).
+
@subsubsection CPU usage reduction
Windows 9x does not correctly use the CPU HLT
@node Sparc32 System emulator invocation
@section Sparc32 System emulator invocation
-Use the executable @file{qemu-system-sparc} to simulate a JavaStation
+Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5
(sun4m architecture). The emulation is somewhat complete.
QEMU emulates the following sun4m peripherals:
The number of peripherals is fixed in the architecture.
-QEMU uses the Proll, a PROM replacement available at
-@url{http://people.redhat.com/@/zaitcev/linux/}. The required
-QEMU-specific patches are included with the sources.
+Since version 0.8.2, QEMU uses OpenBIOS
+@url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable
+firmware implementation. The goal is to implement a 100% IEEE
+1275-1994 (referred to as Open Firmware) compliant firmware.
A sample Linux 2.6 series kernel and ram disk image are available on
-the QEMU web site. Please note that currently neither Linux 2.4
-series, NetBSD, nor OpenBSD kernels work.
+the QEMU web site. Please note that currently NetBSD, OpenBSD or
+Solaris kernels don't work.
@c man begin OPTIONS
Two PL011 UARTs
@item
SMC 91c111 Ethernet adapter
+@item
+PL110 LCD controller
+@item
+PL050 KMI with PS/2 keyboard and mouse.
+@end itemize
+
+The ARM Versatile baseboard is emulated with the following devices:
+
+@itemize @minus
+@item
+ARM926E CPU
+@item
+PL190 Vectored Interrupt Controller
+@item
+Four PL011 UARTs
+@item
+SMC 91c111 Ethernet adapter
+@item
+PL110 LCD controller
+@item
+PL050 KMI with PS/2 keyboard and mouse.
+@item
+PCI host bridge. Note the emulated PCI bridge only provides access to
+PCI memory space. It does not provide access to PCI IO space.
+This means some devices (eg. ne2k_pci NIC) are not useable, and others
+(eg. rtl8139 NIC) are only useable when the guest drivers use the memory
+mapped control registers.
+@item
+PCI OHCI USB controller.
+@item
+LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices.
@end itemize
A Linux 2.6 test image is available on the QEMU web site. More
* Quick Start::
* Wine launch::
* Command line options::
+* Other binaries::
@end menu
@node Quick Start
Act as if the host page size was 'pagesize' bytes
@end table
+@node Other binaries
+@section Other binaries
+
+@command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF
+binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB
+configurations), and arm-uclinux bFLT format binaries.
+
+The binary format is detected automatically.
+
@node compilation
@chapter Compilation from the sources
*/
#include "vl.h"
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
void *get_mmap_addr(unsigned long size)
{
return NULL;
static void get_human_readable_size(char *buf, int buf_size, int64_t size)
{
- char suffixes[NB_SUFFIXES] = "KMGT";
+ static const char suffixes[NB_SUFFIXES] = "KMGT";
int64_t base;
int i;
if (size <= 999) {
- snprintf(buf, buf_size, "%lld", (long long) size);
+ snprintf(buf, buf_size, "%" PRId64, size);
} else {
base = 1024;
for(i = 0; i < NB_SUFFIXES; i++) {
suffixes[i]);
break;
} else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
- snprintf(buf, buf_size, "%lld%c",
- (long long) ((size + (base >> 1)) / base),
+ snprintf(buf, buf_size, "%" PRId64 "%c",
+ ((size + (base >> 1)) / base),
suffixes[i]);
break;
}
printf(", backing_file=%s",
base_filename);
}
- printf(", size=%lld kB\n", (long long) (size / 1024));
+ printf(", size=%" PRId64 " kB\n", (int64_t) (size / 1024));
ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted);
if (ret < 0) {
if (ret == -ENOTSUP) {
memset(buf + n * 512, 0, cluster_size - n * 512);
if (is_not_zero(buf, cluster_size)) {
if (qcow_compress_cluster(out_bs, sector_num, buf) != 0)
- error("error while compressing sector %lld", sector_num);
+ error("error while compressing sector %" PRId64,
+ sector_num);
}
sector_num += n;
}
#ifdef _WIN32
static int64_t get_allocated_file_size(const char *filename)
{
+ typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
+ get_compressed_t get_compressed;
struct _stati64 st;
+
+ /* WinNT support GetCompressedFileSize to determine allocate size */
+ get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
+ if (get_compressed) {
+ DWORD high, low;
+ low = get_compressed(filename, &high);
+ if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
+ return (((int64_t) high) << 32) + low;
+ }
+
if (_stati64(filename, &st) < 0)
return -1;
return st.st_size;
allocated_size);
printf("image: %s\n"
"file format: %s\n"
- "virtual size: %s (%lld bytes)\n"
+ "virtual size: %s (%" PRId64 " bytes)\n"
"disk size: %s\n",
filename, fmt_name, size_buf,
- (long long) (total_sectors * 512),
+ (total_sectors * 512),
dsize_buf);
if (bdrv_is_encrypted(bs))
printf("encrypted: yes\n");
ds->data = screen->pixels;
ds->linesize = screen->pitch;
ds->depth = screen->format->BitsPerPixel;
+ if (ds->depth == 32 && screen->format->Rshift == 0) {
+ ds->bgr = 1;
+ } else {
+ ds->bgr = 0;
+ }
ds->width = w;
ds->height = h;
}
static void sdl_hide_cursor(void)
{
if (kbd_mouse_is_absolute()) {
- SDL_ShowCursor(1);
- SDL_SetCursor(sdl_cursor_hidden);
+ SDL_ShowCursor(1);
+ SDL_SetCursor(sdl_cursor_hidden);
} else {
- SDL_ShowCursor(0);
+ SDL_ShowCursor(0);
}
}
static void sdl_show_cursor(void)
{
if (!kbd_mouse_is_absolute()) {
- SDL_ShowCursor(1);
+ SDL_ShowCursor(1);
}
}
gui_key_modifier_pressed = 0;
if (gui_keysym == 0) {
/* exit/enter grab if pressing Ctrl-Alt */
- if (!gui_grab)
- sdl_grab_start();
- else
+ if (!gui_grab) {
+ /* if the application is not active,
+ do not try to enter grab state. It
+ prevents
+ 'SDL_WM_GrabInput(SDL_GRAB_ON)'
+ from blocking all the application
+ (SDL bug). */
+ if (SDL_GetAppState() & SDL_APPACTIVE)
+ sdl_grab_start();
+ } else {
sdl_grab_end();
+ }
/* SDL does not send back all the
modifiers key, so we must correct it */
reset_keys();
typedef struct TAPState {
VLANClientState *vc;
tap_win32_overlapped_t *handle;
+ HANDLE tap_event;
} TAPState;
static TAPState *tap_win32_state = NULL;
if (size > 0) {
qemu_send_packet(s->vc, buf, size);
tap_win32_free_buffer(s->handle, buf);
+ SetEvent(s->tap_event);
}
}
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"tap: ifname=%s", ifname);
tap_win32_state = s;
+
+ s->tap_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!s->tap_event) {
+ fprintf(stderr, "tap-win32: Failed CreateEvent\n");
+ }
+ qemu_add_wait_object(s->tap_event, NULL, NULL);
return 0;
}
float approx_rsqrt(float a);
float approx_rcp(float a);
void update_fp_status(void);
+void helper_hlt(void);
+void helper_monitor(void);
+void helper_mwait(void);
extern const uint8_t parity_table[256];
extern const uint8_t rclw_table[32];
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
next_eip = env->eip + next_eip_addend;
switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
+ CC_OP = CC_OP_EFLAGS;
break;
case 4: /* 286 call gate */
case 12: /* 386 call gate */
if (dpl < cpl || dpl < rpl)
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
+ CC_OP = CC_OP_EFLAGS;
return;
case 4: /* 286 call gate */
case 12: /* 386 call gate */
if (SIGND(temp))
env->fpus |= 0x200; /* C1 <-- 1 */
+ /* XXX: test fptags too */
expdif = EXPD(temp);
if (expdif == MAXEXPD) {
+#ifdef USE_X86LDOUBLE
+ if (MANTD(temp) == 0x8000000000000000ULL)
+#else
if (MANTD(temp) == 0)
+#endif
env->fpus |= 0x500 /*Infinity*/;
else
env->fpus |= 0x100 /*NaN*/;
v = (uint64_t)a1 * (uint64_t)b1;
*phigh += v;
#ifdef DEBUG_MULDIV
- printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
+ printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n",
a, b, *phigh, *plow);
#endif
}
a0 = (a0 << 1) | qb;
}
#if defined(DEBUG_MULDIV)
- printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n",
+ printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
*phigh, *plow, b, a0, a1);
#endif
*plow = a0;
}
#endif
+void helper_hlt(void)
+{
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+ env->hflags |= HF_HALTED_MASK;
+ env->exception_index = EXCP_HLT;
+ cpu_loop_exit();
+}
+
+void helper_monitor(void)
+{
+ if (ECX != 0)
+ raise_exception(EXCP0D_GPF);
+ /* XXX: store address ? */
+}
+
+void helper_mwait(void)
+{
+ if (ECX != 0)
+ raise_exception(EXCP0D_GPF);
+ /* XXX: not complete but not completely erroneous */
+ if (env->cpu_index != 0 || env->next_cpu != NULL) {
+ /* more than one CPU: do not sleep because another CPU may
+ wake this one */
+ } else {
+ helper_hlt();
+ }
+}
+
float approx_rsqrt(float a)
{
return 1.0 / sqrt(a);
#include <linux/unistd.h>
#include <linux/version.h>
-_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
+int modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+ return syscall(__NR_modify_ldt, func, ptr, bytecount);
+}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
#define modify_ldt_ldt_s user_desc
#ifdef TARGET_X86_64
if (env->hflags & HF_CS64_MASK) {
cpu_fprintf(f,
- "RAX=%016llx RBX=%016llx RCX=%016llx RDX=%016llx\n"
- "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n"
- "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n"
- "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n"
- "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
+ "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
+ "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
+ "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
+ "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
+ "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
if (env->hflags & HF_LMA_MASK) {
for(i = 0; i < 6; i++) {
SegmentCache *sc = &env->segs[i];
- cpu_fprintf(f, "%s =%04x %016llx %08x %08x\n",
+ cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n",
seg_name[i],
sc->selector,
sc->base,
sc->limit,
sc->flags);
}
- cpu_fprintf(f, "LDT=%04x %016llx %08x %08x\n",
+ cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n",
env->ldt.selector,
env->ldt.base,
env->ldt.limit,
env->ldt.flags);
- cpu_fprintf(f, "TR =%04x %016llx %08x %08x\n",
+ cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n",
env->tr.selector,
env->tr.base,
env->tr.limit,
env->tr.flags);
- cpu_fprintf(f, "GDT= %016llx %08x\n",
+ cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n",
env->gdt.base, env->gdt.limit);
- cpu_fprintf(f, "IDT= %016llx %08x\n",
+ cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n",
env->idt.base, env->idt.limit);
- cpu_fprintf(f, "CR0=%08x CR2=%016llx CR3=%016llx CR4=%08x\n",
+ cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
(uint32_t)env->cr[0],
env->cr[2],
env->cr[3],
snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
#ifdef TARGET_X86_64
if (env->hflags & HF_CS64_MASK) {
- cpu_fprintf(f, "CCS=%016llx CCD=%016llx CCO=%-8s\n",
+ cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
env->cc_src, env->cc_dst,
cc_op_name);
} else
} l;
} tmp;
tmp.d = env->fpregs[i].d;
- cpu_fprintf(f, "FPR%d=%016llx %04x",
+ cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
i, tmp.l.lower, tmp.l.upper);
#else
- cpu_fprintf(f, "FPR%d=%016llx",
+ cpu_fprintf(f, "FPR%d=%016" PRIx64,
i, env->fpregs[i].mmx.q);
#endif
if ((i & 1) == 1)
void OPPROTO op_hlt(void)
{
- env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
- env->hflags |= HF_HALTED_MASK;
- env->exception_index = EXCP_HLT;
- cpu_loop_exit();
+ helper_hlt();
+}
+
+void OPPROTO op_monitor(void)
+{
+ helper_monitor();
+}
+
+void OPPROTO op_mwait(void)
+{
+ helper_mwait();
}
void OPPROTO op_debug(void)
int popl_esp_hack; /* for correct popl with esp base handling */
int rip_offset; /* only used in x86_64, but left for simplicity */
int cpuid_features;
+ int cpuid_ext_features;
} DisasContext;
static void gen_eob(DisasContext *s);
break;
case 0xc4: /* pinsrw */
case 0x1c4:
+ s->rip_offset = 1;
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
val = ldub_code(s->pc++);
if (b1) {
break;
case 0x2d6: /* movq2dq */
gen_op_enter_mmx();
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
- offsetof(CPUX86State,fpregs[reg & 7].mmx));
- gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
+ rm = (modrm & 7);
+ gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
+ offsetof(CPUX86State,fpregs[rm].mmx));
+ gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
break;
case 0x3d6: /* movdq2q */
gen_op_enter_mmx();
- rm = (modrm & 7);
- gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx),
- offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
+ rm = (modrm & 7) | REX_B(s);
+ gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx),
+ offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
break;
case 0xd7: /* pmovmskb */
case 0x1d7:
}
} else {
/* generic MMX or SSE operation */
- if (b == 0xf7) {
+ switch(b) {
+ case 0xf7:
/* maskmov : we must prepare A0 */
if (mod != 3)
goto illegal_op;
gen_op_andl_A0_ffff();
}
gen_add_A0_ds_seg(s);
+ break;
+ case 0x70: /* pshufx insn */
+ case 0xc6: /* pshufx insn */
+ case 0xc2: /* compare insns */
+ s->rip_offset = 1;
+ break;
+ default:
+ break;
}
if (is_xmm) {
op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
if (mod != 3) {
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
op2_offset = offsetof(CPUX86State,xmm_t0);
- if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f) ||
+ if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) ||
b == 0xc2)) {
/* specific case for SSE single instructions */
if (b1 == 2) {
modrm = ldub_code(s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
+ rm = modrm & 7;
switch(op) {
case 0: /* sgdt */
- case 1: /* sidt */
if (mod == 3)
goto illegal_op;
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
- if (op == 0)
- gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit));
- else
- gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit));
+ gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit));
gen_op_st_T0_A0[OT_WORD + s->mem_index]();
gen_add_A0_im(s, 2);
- if (op == 0)
- gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base));
- else
- gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base));
+ gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base));
if (!s->dflag)
gen_op_andl_T0_im(0xffffff);
gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
break;
+ case 1:
+ if (mod == 3) {
+ switch (rm) {
+ case 0: /* monitor */
+ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
+ s->cpl != 0)
+ goto illegal_op;
+ gen_jmp_im(pc_start - s->cs_base);
+#ifdef TARGET_X86_64
+ if (s->aflag == 2) {
+ gen_op_movq_A0_reg[R_EBX]();
+ gen_op_addq_A0_AL();
+ } else
+#endif
+ {
+ gen_op_movl_A0_reg[R_EBX]();
+ gen_op_addl_A0_AL();
+ if (s->aflag == 0)
+ gen_op_andl_A0_ffff();
+ }
+ gen_add_A0_ds_seg(s);
+ gen_op_monitor();
+ break;
+ case 1: /* mwait */
+ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
+ s->cpl != 0)
+ goto illegal_op;
+ if (s->cc_op != CC_OP_DYNAMIC) {
+ gen_op_set_cc_op(s->cc_op);
+ s->cc_op = CC_OP_DYNAMIC;
+ }
+ gen_jmp_im(s->pc - s->cs_base);
+ gen_op_mwait();
+ gen_eob(s);
+ break;
+ default:
+ goto illegal_op;
+ }
+ } else { /* sidt */
+ gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
+ gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit));
+ gen_op_st_T0_A0[OT_WORD + s->mem_index]();
+ gen_add_A0_im(s, 2);
+ gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base));
+ if (!s->dflag)
+ gen_op_andl_T0_im(0xffffff);
+ gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
+ }
+ break;
case 2: /* lgdt */
case 3: /* lidt */
if (mod == 3)
} else {
if (mod == 3) {
#ifdef TARGET_X86_64
- if (CODE64(s) && (modrm & 7) == 0) {
+ if (CODE64(s) && rm == 0) {
/* swapgs */
gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base));
gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase));
dc->mem_index = 1 * 4;
}
dc->cpuid_features = env->cpuid_features;
+ dc->cpuid_ext_features = env->cpuid_ext_features;
#ifdef TARGET_X86_64
dc->lma = (flags >> HF_LMA_SHIFT) & 1;
dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
-include ../config-host.mak
-CFLAGS=-Wall -O2 -g #-msse2
+CFLAGS=-Wall -O2 -g
+#CFLAGS+=-msse2
LDFLAGS=
ifeq ($(ARCH),i386)
#define FMTLX "%016lx"
#define X86_64_ONLY(x) x
#else
-#define FMT64X "%016llx"
+#define FMT64X "%016" PRIx64
#define FMTLX "%08lx"
#define X86_64_ONLY(x)
#endif
a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
}
fpu_clear_exceptions();
+ asm volatile("fxam\n"
+ "fstsw %%ax\n"
+ : "=a" (fpus)
+ : "t" (a));
+ printf("fxam(%f)=%04lx\n", a, fpus & 0x4700);
+ fpu_clear_exceptions();
}
void test_fcvt(double a)
test_fcmp(2, 3);
test_fcmp(2, q_nan.d);
test_fcmp(q_nan.d, -1);
+ test_fcmp(-1.0/0.0, -1);
+ test_fcmp(1.0/0.0, -1);
test_fcvt(0.5);
test_fcvt(-0.5);
test_fcvt(1.0/7.0);
test_fcvt(-1.0/9.0);
test_fcvt(32768);
test_fcvt(-1e20);
+ test_fcvt(-1.0/0.0);
+ test_fcvt(1.0/0.0);
+ test_fcvt(q_nan.d);
test_fconst();
test_fbcd(1234567890123456);
test_fbcd(-123451234567890);
r.q[1], r.q[0]);\
}
+/* Force %xmm0 usage to avoid the case where both register index are 0
+ to test intruction decoding more extensively */
#define CVT_OP_XMM2MMX(op)\
{\
- asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq));\
+ asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \
+ : "%xmm0");\
printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\
#op,\
a.q[1], a.q[0],\
CVT_OP_XMM(cvtpd2dq);
CVT_OP_XMM(cvttpd2dq);
+ /* sse/mmx moves */
+ CVT_OP_XMM2MMX(movdq2q);
+ CVT_OP_MMX2XMM(movq2dq);
+
/* int to float */
a.l[0] = -6;
a.l[1] = 2;
#if defined(__linux__)
#include <dirent.h>
#include <sys/ioctl.h>
-#define __user /* new versions of usbdevice_fs.h use this private attribute */
+#include <linux/compiler.h>
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
int vendor_id, int product_id,
const char *product_name, int speed);
static int usb_host_find_device(int *pbus_num, int *paddr,
+ char *product_name, int product_name_size,
const char *devname);
//#define DEBUG
#define USBDEVFS_PATH "/proc/bus/usb"
+#define PRODUCT_NAME_SZ 32
typedef struct USBHostDevice {
USBDevice dev;
#endif
}
+static void usb_host_handle_destroy(USBDevice *dev)
+{
+ USBHostDevice *s = (USBHostDevice *)dev;
+
+ if (s->fd >= 0)
+ close(s->fd);
+ qemu_free(s);
+}
+
static int usb_host_handle_control(USBDevice *dev,
int request,
int value,
char buf[1024];
int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
int bus_num, addr;
+ char product_name[PRODUCT_NAME_SZ];
- if (usb_host_find_device(&bus_num, &addr, devname) < 0)
+ if (usb_host_find_device(&bus_num, &addr,
+ product_name, sizeof(product_name),
+ devname) < 0)
return NULL;
snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
dev->dev.handle_reset = usb_host_handle_reset;
dev->dev.handle_control = usb_host_handle_control;
dev->dev.handle_data = usb_host_handle_data;
+ dev->dev.handle_destroy = usb_host_handle_destroy;
+
+ if (product_name[0] == '\0')
+ snprintf(dev->dev.devname, sizeof(dev->dev.devname),
+ "host:%s", devname);
+ else
+ pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
+ product_name);
+
return (USBDevice *)dev;
}
int product_id;
int bus_num;
int addr;
+ char product_name[PRODUCT_NAME_SZ];
} FindDeviceState;
static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
const char *product_name, int speed)
{
FindDeviceState *s = opaque;
- if (vendor_id == s->vendor_id &&
- product_id == s->product_id) {
+ if ((vendor_id == s->vendor_id &&
+ product_id == s->product_id) ||
+ (bus_num == s->bus_num &&
+ addr == s->addr)) {
+ pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
s->bus_num = bus_num;
s->addr = addr;
return 1;
'bus.addr' (decimal numbers) or
'vendor_id:product_id' (hexa numbers) */
static int usb_host_find_device(int *pbus_num, int *paddr,
+ char *product_name, int product_name_size,
const char *devname)
{
const char *p;
if (p) {
*pbus_num = strtoul(devname, NULL, 0);
*paddr = strtoul(p + 1, NULL, 0);
+ fs.bus_num = *pbus_num;
+ fs.addr = *paddr;
+ ret = usb_host_scan(&fs, usb_host_find_device_scan);
+ if (ret)
+ pstrcpy(product_name, product_name_size, fs.product_name);
return 0;
}
p = strchr(devname, ':');
if (ret) {
*pbus_num = fs.bus_num;
*paddr = fs.addr;
+ pstrcpy(product_name, product_name_size, fs.product_name);
return 0;
}
}
//#define DEBUG_UNUSED_IOPORT
//#define DEBUG_IOPORT
-#if !defined(CONFIG_SOFTMMU)
-#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024)
-#else
#define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024)
-#endif
#ifdef TARGET_PPC
#define DEFAULT_RAM_SIZE 144
/* in ms */
#define GUI_REFRESH_INTERVAL 30
+/* Max number of USB devices that can be specified on the commandline. */
+#define MAX_USB_CMDLINE 8
+
/* XXX: use a two level table to limit memory usage */
#define MAX_IOPORTS 65536
int win2k_install_hack = 0;
#endif
int usb_enabled = 0;
-USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
-USBDevice *vm_usb_hub;
static VLANState *first_vlan;
int smp_cpus = 1;
int vnc_display = -1;
#else
#define MAX_CPUS 1
#endif
+int acpi_enabled = 0;
+int fd_bootchk = 1;
extern int vcpus;
time_t timeoffset = 0;
-int acpi_enabled = 0;
-
char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'};
extern int domid;
return qemu_put_mouse_event_absolute;
}
+/* compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+ union {
+ uint64_t ll;
+ struct {
+#ifdef WORDS_BIGENDIAN
+ uint32_t high, low;
+#else
+ uint32_t low, high;
+#endif
+ } l;
+ } u, res;
+ uint64_t rl, rh;
+
+ u.ll = a;
+ rl = (uint64_t)u.l.low * (uint64_t)b;
+ rh = (uint64_t)u.l.high * (uint64_t)b;
+ rh += (rl >> 32);
+ res.l.high = rh / c;
+ res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+ return res.ll;
+}
+
/***********************************************************/
-/* timers */
+/* real time host monotonic timer */
-#if defined(__powerpc__)
+#define QEMU_TIMER_BASE 1000000000LL
-static inline uint32_t get_tbl(void)
-{
- uint32_t tbl;
- asm volatile("mftb %0" : "=r" (tbl));
- return tbl;
-}
+#ifdef WIN32
-static inline uint32_t get_tbu(void)
-{
- uint32_t tbl;
- asm volatile("mftbu %0" : "=r" (tbl));
- return tbl;
-}
+static int64_t clock_freq;
-int64_t cpu_get_real_ticks(void)
+static void init_get_clock(void)
{
- uint32_t l, h, h1;
- /* NOTE: we test if wrapping has occurred */
- do {
- h = get_tbu();
- l = get_tbl();
- h1 = get_tbu();
- } while (h != h1);
- return ((int64_t)h << 32) | l;
+ LARGE_INTEGER freq;
+ int ret;
+ ret = QueryPerformanceFrequency(&freq);
+ if (ret == 0) {
+ fprintf(stderr, "Could not calibrate ticks\n");
+ exit(1);
+ }
+ clock_freq = freq.QuadPart;
}
-#elif defined(__i386__)
-
-int64_t cpu_get_real_ticks(void)
+static int64_t get_clock(void)
{
-#ifdef _WIN32
LARGE_INTEGER ti;
QueryPerformanceCounter(&ti);
- return ti.QuadPart;
-#else
- int64_t val;
- asm volatile ("rdtsc" : "=A" (val));
- return val;
-#endif
+ return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
}
-#elif defined(__x86_64__)
-
-int64_t cpu_get_real_ticks(void)
-{
- uint32_t low,high;
- int64_t val;
- asm volatile("rdtsc" : "=a" (low), "=d" (high));
- val = high;
- val <<= 32;
- val |= low;
- return val;
-}
+#else
-#elif defined(__ia64)
+static int use_rt_clock;
-int64_t cpu_get_real_ticks(void)
+static void init_get_clock(void)
{
- int64_t val;
- asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
- return val;
+ use_rt_clock = 0;
+#if defined(__linux__)
+ {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ use_rt_clock = 1;
+ }
+ }
+#endif
}
-#elif defined(__s390__)
-
-int64_t cpu_get_real_ticks(void)
+static int64_t get_clock(void)
{
- int64_t val;
- asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
- return val;
+#if defined(__linux__)
+ if (use_rt_clock) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+ } else
+#endif
+ {
+ /* XXX: using gettimeofday leads to problems if the date
+ changes, so it should be avoided. */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+ }
}
-#else
-#error unsupported CPU
#endif
+/***********************************************************/
+/* guest cycle counter */
+
static int64_t cpu_ticks_prev;
static int64_t cpu_ticks_offset;
+static int64_t cpu_clock_offset;
static int cpu_ticks_enabled;
-static inline int64_t cpu_get_ticks(void)
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
{
if (!cpu_ticks_enabled) {
return cpu_ticks_offset;
}
}
+/* return the host CPU monotonic timer and handle stop/restart */
+static int64_t cpu_get_clock(void)
+{
+ int64_t ti;
+ if (!cpu_ticks_enabled) {
+ return cpu_clock_offset;
+ } else {
+ ti = get_clock();
+ return ti + cpu_clock_offset;
+ }
+}
+
/* enable cpu_get_ticks() */
void cpu_enable_ticks(void)
{
if (!cpu_ticks_enabled) {
cpu_ticks_offset -= cpu_get_real_ticks();
+ cpu_clock_offset -= get_clock();
cpu_ticks_enabled = 1;
}
}
{
if (cpu_ticks_enabled) {
cpu_ticks_offset = cpu_get_ticks();
+ cpu_clock_offset = cpu_get_clock();
cpu_ticks_enabled = 0;
}
}
-#ifdef _WIN32
-void cpu_calibrate_ticks(void)
-{
- LARGE_INTEGER freq;
- int ret;
-
- ret = QueryPerformanceFrequency(&freq);
- if (ret == 0) {
- fprintf(stderr, "Could not calibrate ticks\n");
- exit(1);
- }
- ticks_per_sec = freq.QuadPart;
-}
-
-#else
-static int64_t get_clock(void)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000000LL + tv.tv_usec;
-}
-
-void cpu_calibrate_ticks(void)
-{
- int64_t usec, ticks;
-
- usec = get_clock();
- ticks = cpu_get_real_ticks();
- usleep(50 * 1000);
- usec = get_clock() - usec;
- ticks = cpu_get_real_ticks() - ticks;
- ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec;
-}
-#endif /* !_WIN32 */
-
-/* compute with 96 bit intermediate result: (a*b)/c */
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
-{
- union {
- uint64_t ll;
- struct {
-#ifdef WORDS_BIGENDIAN
- uint32_t high, low;
-#else
- uint32_t low, high;
-#endif
- } l;
- } u, res;
- uint64_t rl, rh;
-
- u.ll = a;
- rl = (uint64_t)u.l.low * (uint64_t)b;
- rh = (uint64_t)u.l.high * (uint64_t)b;
- rh += (rl >> 32);
- res.l.high = rh / c;
- res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
- return res.ll;
-}
-
+/***********************************************************/
+/* timers */
+
#define QEMU_TIMER_REALTIME 0
#define QEMU_TIMER_VIRTUAL 1
{
switch(clock->type) {
case QEMU_TIMER_REALTIME:
-#ifdef _WIN32
- return GetTickCount();
-#else
- {
- struct tms tp;
-
- /* Note that using gettimeofday() is not a good solution
- for timers because its value change when the date is
- modified. */
- if (timer_freq == 100) {
- return times(&tp) * 10;
- } else {
- return ((int64_t)times(&tp) * 1000) / timer_freq;
- }
- }
-#endif
+ return get_clock() / 1000000;
default:
case QEMU_TIMER_VIRTUAL:
- return cpu_get_ticks();
+ return cpu_get_clock();
}
}
+static void init_timers(void)
+{
+ init_get_clock();
+ ticks_per_sec = QEMU_TIMER_BASE;
+ rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
+ vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
+}
+
/* save a timer */
void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
{
delta_max = delta;
delta_cum += delta;
if (++count == DISP_FREQ) {
- printf("timer: min=%lld us max=%lld us avg=%lld us avg_freq=%0.3f Hz\n",
+ printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
muldiv64(delta_min, 1000000, ticks_per_sec),
muldiv64(delta_max, 1000000, ticks_per_sec),
muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec),
#endif /* !CONFIG_DM */
-static void init_timers(void)
+static void init_timer_alarm(void)
{
- rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
- vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
-
#ifdef _WIN32
{
int count=0;
perror("failed CreateEvent");
exit(1);
}
- ResetEvent(host_alarm);
+ qemu_add_wait_object(host_alarm, NULL, NULL);
}
pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
#else
static int term_got_escape, client_index;
static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
-int term_fifo_size;
+static int term_fifo_size;
+static int term_timestamps;
+static int64_t term_timestamps_start;
void term_print_help(void)
{
"C-a x exit emulator\n"
"C-a s save disk data back to file (if -snapshot)\n"
"C-a b send break (magic sysrq)\n"
+ "C-a t toggle console timestamps\n"
"C-a c switch between console and monitor\n"
"C-a C-a send C-a\n"
);
goto send_char;
}
break;
+ case 't':
+ term_timestamps = !term_timestamps;
+ term_timestamps_start = -1;
+ break;
case TERM_ESCAPE:
goto send_char;
}
stdio_received_byte(buf[0]);
}
+static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ FDCharDriver *s = chr->opaque;
+ if (!term_timestamps) {
+ return unix_write(s->fd_out, buf, len);
+ } else {
+ int i;
+ char buf1[64];
+
+ for(i = 0; i < len; i++) {
+ unix_write(s->fd_out, buf + i, 1);
+ if (buf[i] == '\n') {
+ int64_t ti;
+ int secs;
+
+ ti = get_clock();
+ if (term_timestamps_start == -1)
+ term_timestamps_start = ti;
+ ti -= term_timestamps_start;
+ secs = ti / 1000000000;
+ snprintf(buf1, sizeof(buf1),
+ "[%02d:%02d:%02d.%03d] ",
+ secs / 3600,
+ (secs / 60) % 60,
+ secs % 60,
+ (int)((ti / 1000000) % 1000));
+ unix_write(s->fd_out, buf1, strlen(buf1));
+ }
+ }
+ return len;
+ }
+}
+
/* init terminal so that we can grab keys */
static struct termios oldtty;
static int old_fd0_flags;
if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
return NULL;
chr = qemu_chr_open_fd(0, 1);
+ chr->chr_write = stdio_write;
if (stdio_nb_clients == 0)
qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
client_index = stdio_nb_clients;
free(chr);
return NULL;
}
- return chr;
+ return chr;
+}
+
+CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+{
+ CharDriverState *chr;
+ WinCharState *s;
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ if (!chr)
+ return NULL;
+ s = qemu_mallocz(sizeof(WinCharState));
+ if (!s) {
+ free(chr);
+ return NULL;
+ }
+ s->hcom = fd_out;
+ chr->opaque = s;
+ chr->chr_write = win_chr_write;
+ chr->chr_add_read_handler = win_chr_add_read_handler;
+ return chr;
+}
+
+CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
+{
+ HANDLE fd_out;
+
+ fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fd_out == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ return qemu_chr_open_win_file(fd_out);
+}
+#endif
+
+/***********************************************************/
+/* UDP Net console */
+
+typedef struct {
+ IOCanRWHandler *fd_can_read;
+ IOReadHandler *fd_read;
+ void *fd_opaque;
+ int fd;
+ struct sockaddr_in daddr;
+ char buf[1024];
+ int bufcnt;
+ int bufptr;
+ int max_size;
+} NetCharDriver;
+
+static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ NetCharDriver *s = chr->opaque;
+
+ return sendto(s->fd, buf, len, 0,
+ (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
+}
+
+static int udp_chr_read_poll(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ NetCharDriver *s = chr->opaque;
+
+ s->max_size = s->fd_can_read(s->fd_opaque);
+
+ /* If there were any stray characters in the queue process them
+ * first
+ */
+ while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+ s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+ s->bufptr++;
+ s->max_size = s->fd_can_read(s->fd_opaque);
+ }
+ return s->max_size;
+}
+
+static void udp_chr_read(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ NetCharDriver *s = chr->opaque;
+
+ if (s->max_size == 0)
+ return;
+ s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
+ s->bufptr = s->bufcnt;
+ if (s->bufcnt <= 0)
+ return;
+
+ s->bufptr = 0;
+ while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+ s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+ s->bufptr++;
+ s->max_size = s->fd_can_read(s->fd_opaque);
+ }
+}
+
+static void udp_chr_add_read_handler(CharDriverState *chr,
+ IOCanRWHandler *fd_can_read,
+ IOReadHandler *fd_read, void *opaque)
+{
+ NetCharDriver *s = chr->opaque;
+
+ if (s->fd >= 0) {
+ s->fd_can_read = fd_can_read;
+ s->fd_read = fd_read;
+ s->fd_opaque = opaque;
+ qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
+ udp_chr_read, NULL, chr);
+ }
+}
+
+int parse_host_port(struct sockaddr_in *saddr, const char *str);
+int parse_host_src_port(struct sockaddr_in *haddr,
+ struct sockaddr_in *saddr,
+ const char *str);
+
+CharDriverState *qemu_chr_open_udp(const char *def)
+{
+ CharDriverState *chr = NULL;
+ NetCharDriver *s = NULL;
+ int fd = -1;
+ struct sockaddr_in saddr;
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ if (!chr)
+ goto return_err;
+ s = qemu_mallocz(sizeof(NetCharDriver));
+ if (!s)
+ goto return_err;
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("socket(PF_INET, SOCK_DGRAM)");
+ goto return_err;
+ }
+
+ if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
+ printf("Could not parse: %s\n", def);
+ goto return_err;
+ }
+
+ if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+ {
+ perror("bind");
+ goto return_err;
+ }
+
+ s->fd = fd;
+ s->bufcnt = 0;
+ s->bufptr = 0;
+ chr->opaque = s;
+ chr->chr_write = udp_chr_write;
+ chr->chr_add_read_handler = udp_chr_add_read_handler;
+ return chr;
+
+return_err:
+ if (chr)
+ free(chr);
+ if (s)
+ free(s);
+ if (fd >= 0)
+ closesocket(fd);
+ return NULL;
+}
+
+/***********************************************************/
+/* TCP Net console */
+
+typedef struct {
+ IOCanRWHandler *fd_can_read;
+ IOReadHandler *fd_read;
+ void *fd_opaque;
+ int fd, listen_fd;
+ int connected;
+ int max_size;
+ int do_telnetopt;
+} TCPCharDriver;
+
+static void tcp_chr_accept(void *opaque);
+
+static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ TCPCharDriver *s = chr->opaque;
+ if (s->connected) {
+ return send_all(s->fd, buf, len);
+ } else {
+ /* XXX: indicate an error ? */
+ return len;
+ }
+}
+
+static int tcp_chr_read_poll(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ TCPCharDriver *s = chr->opaque;
+ if (!s->connected)
+ return 0;
+ s->max_size = s->fd_can_read(s->fd_opaque);
+ return s->max_size;
+}
+
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+ TCPCharDriver *s,
+ char *buf, int *size)
+{
+ /* Handle any telnet client's basic IAC options to satisfy char by
+ * char mode with no echo. All IAC options will be removed from
+ * the buf and the do_telnetopt variable will be used to track the
+ * state of the width of the IAC information.
+ *
+ * IAC commands come in sets of 3 bytes with the exception of the
+ * "IAC BREAK" command and the double IAC.
+ */
+
+ int i;
+ int j = 0;
+
+ for (i = 0; i < *size; i++) {
+ if (s->do_telnetopt > 1) {
+ if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+ /* Double IAC means send an IAC */
+ if (j != i)
+ buf[j] = buf[i];
+ j++;
+ s->do_telnetopt = 1;
+ } else {
+ if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+ /* Handle IAC break commands by sending a serial break */
+ chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
+ s->do_telnetopt++;
+ }
+ s->do_telnetopt++;
+ }
+ if (s->do_telnetopt >= 4) {
+ s->do_telnetopt = 1;
+ }
+ } else {
+ if ((unsigned char)buf[i] == IAC) {
+ s->do_telnetopt = 2;
+ } else {
+ if (j != i)
+ buf[j] = buf[i];
+ j++;
+ }
+ }
+ }
+ *size = j;
+}
+
+static void tcp_chr_read(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ TCPCharDriver *s = chr->opaque;
+ uint8_t buf[1024];
+ int len, size;
+
+ if (!s->connected || s->max_size <= 0)
+ return;
+ len = sizeof(buf);
+ if (len > s->max_size)
+ len = s->max_size;
+ size = recv(s->fd, buf, len, 0);
+ if (size == 0) {
+ /* connection closed */
+ s->connected = 0;
+ if (s->listen_fd >= 0) {
+ qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+ }
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+ closesocket(s->fd);
+ s->fd = -1;
+ } else if (size > 0) {
+ if (s->do_telnetopt)
+ tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+ if (size > 0)
+ s->fd_read(s->fd_opaque, buf, size);
+ }
+}
+
+static void tcp_chr_add_read_handler(CharDriverState *chr,
+ IOCanRWHandler *fd_can_read,
+ IOReadHandler *fd_read, void *opaque)
+{
+ TCPCharDriver *s = chr->opaque;
+
+ s->fd_can_read = fd_can_read;
+ s->fd_read = fd_read;
+ s->fd_opaque = opaque;
+}
+
+static void tcp_chr_connect(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ TCPCharDriver *s = chr->opaque;
+
+ s->connected = 1;
+ qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
+ tcp_chr_read, NULL, chr);
+}
+
+#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+static void tcp_chr_telnet_init(int fd)
+{
+ char buf[3];
+ /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+ IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
+ send(fd, (char *)buf, 3, 0);
+ IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
+ send(fd, (char *)buf, 3, 0);
+ IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
+ send(fd, (char *)buf, 3, 0);
+ IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
+ send(fd, (char *)buf, 3, 0);
+}
+
+static void tcp_chr_accept(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ TCPCharDriver *s = chr->opaque;
+ struct sockaddr_in saddr;
+ socklen_t len;
+ int fd;
+
+ for(;;) {
+ len = sizeof(saddr);
+ fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
+ if (fd < 0 && errno != EINTR) {
+ return;
+ } else if (fd >= 0) {
+ if (s->do_telnetopt)
+ tcp_chr_telnet_init(fd);
+ break;
+ }
+ }
+ socket_set_nonblock(fd);
+ s->fd = fd;
+ qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+ tcp_chr_connect(chr);
}
-CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+static void tcp_chr_close(CharDriverState *chr)
{
- CharDriverState *chr;
- WinCharState *s;
+ TCPCharDriver *s = chr->opaque;
+ if (s->fd >= 0)
+ closesocket(s->fd);
+ if (s->listen_fd >= 0)
+ closesocket(s->listen_fd);
+ qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_tcp(const char *host_str,
+ int is_telnet)
+{
+ CharDriverState *chr = NULL;
+ TCPCharDriver *s = NULL;
+ int fd = -1, ret, err, val;
+ int is_listen = 0;
+ int is_waitconnect = 1;
+ const char *ptr;
+ struct sockaddr_in saddr;
+
+ if (parse_host_port(&saddr, host_str) < 0)
+ goto fail;
+
+ ptr = host_str;
+ while((ptr = strchr(ptr,','))) {
+ ptr++;
+ if (!strncmp(ptr,"server",6)) {
+ is_listen = 1;
+ } else if (!strncmp(ptr,"nowait",6)) {
+ is_waitconnect = 0;
+ } else {
+ printf("Unknown option: %s\n", ptr);
+ goto fail;
+ }
+ }
+ if (!is_listen)
+ is_waitconnect = 0;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
- return NULL;
- s = qemu_mallocz(sizeof(WinCharState));
- if (!s) {
- free(chr);
- return NULL;
- }
- s->hcom = fd_out;
- chr->opaque = s;
- chr->chr_write = win_chr_write;
- chr->chr_add_read_handler = win_chr_add_read_handler;
- return chr;
-}
+ goto fail;
+ s = qemu_mallocz(sizeof(TCPCharDriver));
+ if (!s)
+ goto fail;
-CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
-{
- HANDLE fd_out;
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ goto fail;
+
+ if (!is_waitconnect)
+ socket_set_nonblock(fd);
+
+ s->connected = 0;
+ s->fd = -1;
+ s->listen_fd = -1;
+ if (is_listen) {
+ /* allow fast reuse */
+ val = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+
+ ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+ if (ret < 0)
+ goto fail;
+ ret = listen(fd, 0);
+ if (ret < 0)
+ goto fail;
+ s->listen_fd = fd;
+ qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+ if (is_telnet)
+ s->do_telnetopt = 1;
+ } else {
+ for(;;) {
+ ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+ if (ret < 0) {
+ err = socket_error();
+ if (err == EINTR || err == EWOULDBLOCK) {
+ } else if (err == EINPROGRESS) {
+ break;
+ } else {
+ goto fail;
+ }
+ } else {
+ s->connected = 1;
+ break;
+ }
+ }
+ s->fd = fd;
+ if (s->connected)
+ tcp_chr_connect(chr);
+ else
+ qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
+ }
- fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
- OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (fd_out == INVALID_HANDLE_VALUE)
- return NULL;
+ chr->opaque = s;
+ chr->chr_write = tcp_chr_write;
+ chr->chr_add_read_handler = tcp_chr_add_read_handler;
+ chr->chr_close = tcp_chr_close;
+ if (is_listen && is_waitconnect) {
+ printf("QEMU waiting for connection on: %s\n", host_str);
+ tcp_chr_accept(chr);
+ socket_set_nonblock(s->listen_fd);
+ }
- return qemu_chr_open_win_file(fd_out);
+ return chr;
+ fail:
+ if (fd >= 0)
+ closesocket(fd);
+ qemu_free(s);
+ qemu_free(chr);
+ return NULL;
}
-#endif
CharDriverState *qemu_chr_open(const char *filename)
{
} else if (!strcmp(filename, "null")) {
return qemu_chr_open_null();
} else
+ if (strstart(filename, "tcp:", &p)) {
+ return qemu_chr_open_tcp(p, 0);
+ } else
+ if (strstart(filename, "telnet:", &p)) {
+ return qemu_chr_open_tcp(p, 1);
+ } else
+ if (strstart(filename, "udp:", &p)) {
+ return qemu_chr_open_udp(p);
+ } else
#ifndef _WIN32
if (strstart(filename, "file:", &p)) {
return qemu_chr_open_file_out(p);
return 0;
}
+int parse_host_src_port(struct sockaddr_in *haddr,
+ struct sockaddr_in *saddr,
+ const char *input_str)
+{
+ char *str = strdup(input_str);
+ char *host_str = str;
+ char *src_str;
+ char *ptr;
+
+ /*
+ * Chop off any extra arguments at the end of the string which
+ * would start with a comma, then fill in the src port information
+ * if it was provided else use the "any address" and "any port".
+ */
+ if ((ptr = strchr(str,',')))
+ *ptr = '\0';
+
+ if ((src_str = strchr(input_str,'@'))) {
+ *src_str = '\0';
+ src_str++;
+ }
+
+ if (parse_host_port(haddr, host_str) < 0)
+ goto fail;
+
+ if (!src_str || *src_str == '\0')
+ src_str = ":0";
+
+ if (parse_host_port(saddr, src_str) < 0)
+ goto fail;
+
+ free(str);
+ return(0);
+
+fail:
+ free(str);
+ return -1;
+}
+
int parse_host_port(struct sockaddr_in *saddr, const char *str)
{
char buf[512];
socket_set_nonblock(fd);
return fd;
fail:
- if (fd>=0) close(fd);
+ if (fd >= 0)
+ closesocket(fd);
return -1;
}
}
s1 = net_socket_fd_init(s->vlan, fd, 1);
if (!s1) {
- close(fd);
+ closesocket(fd);
} else {
snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
"socket: connection from %s:%d",
/***********************************************************/
/* USB devices */
+static USBPort *used_usb_ports;
+static USBPort *free_usb_ports;
+
+/* ??? Maybe change this to register a hub to keep track of the topology. */
+void qemu_register_usb_port(USBPort *port, void *opaque, int index,
+ usb_attachfn attach)
+{
+ port->opaque = opaque;
+ port->index = index;
+ port->attach = attach;
+ port->next = free_usb_ports;
+ free_usb_ports = port;
+}
+
static int usb_device_add(const char *devname)
{
const char *p;
USBDevice *dev;
- int i;
+ USBPort *port;
- if (!vm_usb_hub)
- return -1;
- for(i = 0;i < MAX_VM_USB_PORTS; i++) {
- if (!vm_usb_ports[i]->dev)
- break;
- }
- if (i == MAX_VM_USB_PORTS)
+ if (!free_usb_ports)
return -1;
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(p);
- if (!dev)
- return -1;
} else if (!strcmp(devname, "mouse")) {
dev = usb_mouse_init();
- if (!dev)
- return -1;
} else if (!strcmp(devname, "tablet")) {
dev = usb_tablet_init();
- if (!dev)
- return -1;
+ } else if (strstart(devname, "disk:", &p)) {
+ dev = usb_msd_init(p);
} else {
return -1;
}
- usb_attach(vm_usb_ports[i], dev);
+ if (!dev)
+ return -1;
+
+ /* Find a USB port to add the device to. */
+ port = free_usb_ports;
+ if (!port->next) {
+ USBDevice *hub;
+
+ /* Create a new hub and chain it on. */
+ free_usb_ports = NULL;
+ port->next = used_usb_ports;
+ used_usb_ports = port;
+
+ hub = usb_hub_init(VM_USB_HUB_SIZE);
+ usb_attach(port, hub);
+ port = free_usb_ports;
+ }
+
+ free_usb_ports = port->next;
+ port->next = used_usb_ports;
+ used_usb_ports = port;
+ usb_attach(port, dev);
return 0;
}
static int usb_device_del(const char *devname)
{
+ USBPort *port;
+ USBPort **lastp;
USBDevice *dev;
- int bus_num, addr, i;
+ int bus_num, addr;
const char *p;
- if (!vm_usb_hub)
+ if (!used_usb_ports)
return -1;
p = strchr(devname, '.');
addr = strtoul(p + 1, NULL, 0);
if (bus_num != 0)
return -1;
- for(i = 0;i < MAX_VM_USB_PORTS; i++) {
- dev = vm_usb_ports[i]->dev;
- if (dev && dev->addr == addr)
- break;
+
+ lastp = &used_usb_ports;
+ port = used_usb_ports;
+ while (port && port->dev->addr != addr) {
+ lastp = &port->next;
+ port = port->next;
}
- if (i == MAX_VM_USB_PORTS)
+
+ if (!port)
return -1;
- usb_attach(vm_usb_ports[i], NULL);
+
+ dev = port->dev;
+ *lastp = port->next;
+ usb_attach(port, NULL);
+ dev->handle_destroy(dev);
+ port->next = free_usb_ports;
+ free_usb_ports = port;
return 0;
}
void usb_info(void)
{
USBDevice *dev;
- int i;
+ USBPort *port;
const char *speed_str;
- if (!vm_usb_hub) {
+ if (!usb_enabled) {
term_printf("USB support not enabled\n");
return;
}
- for(i = 0; i < MAX_VM_USB_PORTS; i++) {
- dev = vm_usb_ports[i]->dev;
- if (dev) {
- term_printf("Hub port %d:\n", i);
- switch(dev->speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
- break;
- case USB_SPEED_FULL:
- speed_str = "12";
- break;
- case USB_SPEED_HIGH:
- speed_str = "480";
- break;
- default:
- speed_str = "?";
- break;
- }
- term_printf(" Device %d.%d, speed %s Mb/s\n",
- 0, dev->addr, speed_str);
+ for (port = used_usb_ports; port; port = port->next) {
+ dev = port->dev;
+ if (!dev)
+ continue;
+ switch(dev->speed) {
+ case USB_SPEED_LOW:
+ speed_str = "1.5";
+ break;
+ case USB_SPEED_FULL:
+ speed_str = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed_str = "480";
+ break;
+ default:
+ speed_str = "?";
+ break;
}
+ term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n",
+ 0, dev->addr, speed_str, dev->devname);
}
}
ds->dpy_refresh = dumb_refresh;
}
-#if !defined(CONFIG_SOFTMMU)
-/***********************************************************/
-/* cpu signal handler */
-static void host_segv_handler(int host_signum, siginfo_t *info,
- void *puc)
-{
- if (cpu_signal_handler(host_signum, info, puc))
- return;
- if (stdio_nb_clients > 0)
- term_exit();
- abort();
-}
-#endif
-
/***********************************************************/
/* I/O handling */
}
}
+#ifdef _WIN32
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+ int num;
+ HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+ WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+ void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+ WaitObjects *w = &wait_objects;
+
+ if (w->num >= MAXIMUM_WAIT_OBJECTS)
+ return -1;
+ w->events[w->num] = handle;
+ w->func[w->num] = func;
+ w->opaque[w->num] = opaque;
+ w->num++;
+ return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+ int i, found;
+ WaitObjects *w = &wait_objects;
+
+ found = 0;
+ for (i = 0; i < w->num; i++) {
+ if (w->events[i] == handle)
+ found = 1;
+ if (found) {
+ w->events[i] = w->events[i + 1];
+ w->func[i] = w->func[i + 1];
+ w->opaque[i] = w->opaque[i + 1];
+ }
+ }
+ if (found)
+ w->num--;
+}
+#endif
+
/***********************************************************/
/* savevm/loadvm support */
/* FPU */
for(i = 0; i < TARGET_FPREGS; i++) {
union {
- TARGET_FPREG_T f;
- target_ulong i;
+ float32 f;
+ uint32_t i;
} u;
u.f = env->fpr[i];
- qemu_put_betl(f, u.i);
+ qemu_put_be32(f, u.i);
}
qemu_put_betls(f, &env->pc);
/* FPU */
for(i = 0; i < TARGET_FPREGS; i++) {
union {
- TARGET_FPREG_T f;
- target_ulong i;
+ float32 f;
+ uint32_t i;
} u;
- u.i = qemu_get_betl(f);
+ u.i = qemu_get_be32(f);
env->fpr[i] = u.f;
}
}
#ifdef _WIN32
if (ret == 0 && timeout > 0) {
- int err;
- HANDLE hEvents[1];
-
- hEvents[0] = host_alarm;
- ret = WaitForMultipleObjects(1, hEvents, FALSE, timeout);
- switch(ret) {
- case WAIT_OBJECT_0 + 0:
- break;
- case WAIT_TIMEOUT:
- break;
- default:
- err = GetLastError();
- fprintf(stderr, "Wait error %d %d\n", ret, err);
- break;
- }
+ int err;
+ WaitObjects *w = &wait_objects;
+
+ ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
+ if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+ if (w->func[ret - WAIT_OBJECT_0])
+ w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+ } else if (ret == WAIT_TIMEOUT) {
+ } else {
+ err = GetLastError();
+ fprintf(stderr, "Wait error %d %d\n", ret, err);
+ }
}
#endif
/* poll any events */
#endif /* !CONFIG_DM */
"-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n"
"-snapshot write to temporary files instead of disk image files\n"
+#ifdef TARGET_I386
+ "-no-fd-bootchk disable boot signature checking for floppy disks\n"
+#endif
"-m megs set virtual RAM size to megs MB [default=%d]\n"
"-smp n set the number of CPUs to 'n' [default=1]\n"
"-nographic disable graphical output and redirect serial I/Os to console\n"
" translation (t=none or lba) (usually qemu can guess them)\n"
"-L path set the directory for the BIOS and VGA BIOS\n"
#ifdef USE_KQEMU
+ "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n"
"-no-kqemu disable KQEMU kernel module usage\n"
#endif
#ifdef USE_CODE_COPY
#ifdef TARGET_I386
"-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
" (default is CL-GD5446 PCI VGA)\n"
+ "-no-acpi disable ACPI\n"
#endif
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
"-vnc display start a VNC server on display\n"
"\n"
"When using -nographic, press 'ctrl-a h' to get some help.\n"
,
-#ifdef CONFIG_SOFTMMU
"qemu",
-#else
- "qemu-fast",
-#endif
DEFAULT_RAM_SIZE,
#ifndef _WIN32
DEFAULT_NETWORK_SCRIPT,
#endif
DEFAULT_GDBSTUB_PORT,
"/tmp/qemu.log");
-#ifndef CONFIG_SOFTMMU
- printf("\n"
- "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n"
- "work. Please use the 'qemu' executable to have a more accurate (but slower)\n"
- "PC emulation.\n");
-#endif
exit(1);
}
#endif /* !CONFIG_DM */
QEMU_OPTION_boot,
QEMU_OPTION_snapshot,
+#ifdef TARGET_I386
+ QEMU_OPTION_no_fd_bootchk,
+#endif
QEMU_OPTION_m,
QEMU_OPTION_nographic,
#ifdef HAS_AUDIO
QEMU_OPTION_usbdevice,
QEMU_OPTION_smp,
QEMU_OPTION_vnc,
- QEMU_OPTION_vncviewer,
+ QEMU_OPTION_no_acpi,
QEMU_OPTION_d,
QEMU_OPTION_vcpus,
QEMU_OPTION_timeoffset,
QEMU_OPTION_acpi,
+ QEMU_OPTION_vncviewer,
};
typedef struct QEMUOption {
#endif /* !CONFIG_DM */
{ "boot", HAS_ARG, QEMU_OPTION_boot },
{ "snapshot", 0, QEMU_OPTION_snapshot },
+#ifdef TARGET_I386
+ { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk },
+#endif
{ "m", HAS_ARG, QEMU_OPTION_m },
{ "nographic", 0, QEMU_OPTION_nographic },
{ "k", HAS_ARG, QEMU_OPTION_k },
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
+ { "no-acpi", 0, QEMU_OPTION_no_acpi },
{ "d", HAS_ARG, QEMU_OPTION_d },
{ "vcpus", 1, QEMU_OPTION_vcpus },
}
#endif
+#ifdef _WIN32
+static BOOL WINAPI qemu_ctrl_handler(DWORD type)
+{
+ exit(STATUS_CONTROL_C_EXIT);
+ return TRUE;
+}
+#endif
+
#define MAX_NET_CLIENTS 32
#include <xg_private.h>
int parallel_device_index;
const char *loadvm = NULL;
QEMUMachine *machine;
- char usb_devices[MAX_VM_USB_PORTS][128];
+ char usb_devices[MAX_USB_CMDLINE][128];
int usb_devices_index;
unsigned long nr_pages;
xen_pfn_t *page_array;
char qemu_dm_logfilename[64];
LIST_INIT (&vm_change_state_head);
-#if !defined(CONFIG_SOFTMMU)
- /* we never want that malloc() uses mmap() */
- mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
+#ifndef _WIN32
+ {
+ struct sigaction act;
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+ }
+#else
+ SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+ /* Note: cpu_interrupt() is currently not SMP safe, so we force
+ QEMU to run on a single CPU */
+ {
+ HANDLE h;
+ DWORD mask, smask;
+ int i;
+ h = GetCurrentProcess();
+ if (GetProcessAffinityMask(h, &mask, &smask)) {
+ for(i = 0; i < 32; i++) {
+ if (mask & (1 << i))
+ break;
+ }
+ if (i != 32) {
+ mask = 1 << i;
+ SetProcessAffinityMask(h, mask);
+ }
+ }
+ }
#endif
+
register_machines();
machine = first_machine;
initrd_filename = NULL;
case QEMU_OPTION_fdb:
fd_filename[1] = optarg;
break;
+#ifdef TARGET_I386
+ case QEMU_OPTION_no_fd_bootchk:
+ fd_bootchk = 0;
+ break;
+#endif
#ifdef USE_CODE_COPY
case QEMU_OPTION_no_code_copy:
code_copy_enabled = 0;
break;
case QEMU_OPTION_usbdevice:
usb_enabled = 1;
- if (usb_devices_index >= MAX_VM_USB_PORTS) {
+ if (usb_devices_index >= MAX_USB_CMDLINE) {
fprintf(stderr, "Too many USB devices\n");
exit(1);
}
exit(1);
}
break;
- case QEMU_OPTION_vncviewer:
- vncviewer++;
+ case QEMU_OPTION_no_acpi:
+ acpi_enabled = 0;
break;
case QEMU_OPTION_domainname:
strncat(domain_name, optarg, sizeof(domain_name) - 20);
case QEMU_OPTION_acpi:
acpi_enabled = 1;
break;
+ case QEMU_OPTION_vncviewer:
+ vncviewer++;
+ break;
}
}
}
}
#endif /* !CONFIG_DM */
-#if !defined(CONFIG_SOFTMMU)
- /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
- {
- static uint8_t stdout_buf[4096];
- setvbuf(stdout, stdout_buf, _IOLBF, sizeof(stdout_buf));
- }
-#else
setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
+ init_timers();
+ init_timer_alarm();
+
#ifdef _WIN32
socket_init();
#endif
#endif
#else /* !CONFIG_DM */
-#ifdef CONFIG_SOFTMMU
phys_ram_base = qemu_vmalloc(phys_ram_size);
if (!phys_ram_base) {
fprintf(stderr, "Could not allocate physical memory\n");
exit(1);
}
-#else
- /* as we must map the same page at several addresses, we must use
- a fd */
- {
- const char *tmpdir;
-
- tmpdir = getenv("QEMU_TMPDIR");
- if (!tmpdir)
- tmpdir = "/tmp";
- snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir);
- if (mkstemp(phys_ram_file) < 0) {
- fprintf(stderr, "Could not create temporary memory file '%s'\n",
- phys_ram_file);
- exit(1);
- }
- phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
- if (phys_ram_fd < 0) {
- fprintf(stderr, "Could not open temporary memory file '%s'\n",
- phys_ram_file);
- exit(1);
- }
- ftruncate(phys_ram_fd, phys_ram_size);
- unlink(phys_ram_file);
- phys_ram_base = mmap(get_mmap_addr(phys_ram_size),
- phys_ram_size,
- PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED,
- phys_ram_fd, 0);
- if (phys_ram_base == MAP_FAILED) {
- fprintf(stderr, "Could not map physical memory\n");
- exit(1);
- }
- }
-#endif
#endif /* !CONFIG_DM */
}
}
- /* init USB devices */
- if (usb_enabled) {
- vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS);
- for(i = 0; i < usb_devices_index; i++) {
- if (usb_device_add(usb_devices[i]) < 0) {
- fprintf(stderr, "Warning: could not add USB device %s\n",
- usb_devices[i]);
- }
- }
- }
-
register_savevm("timer", 0, 1, timer_save, timer_load, NULL);
register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
init_ioports();
- cpu_calibrate_ticks();
/* terminal init */
if (nographic) {
exit(1);
}
if (!strcmp(serial_devices[i], "vc"))
- qemu_chr_printf(serial_hds[i], "serial%d console\n", i);
+ qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
}
}
exit(1);
}
if (!strcmp(parallel_devices[i], "vc"))
- qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i);
+ qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
}
}
- /* setup cpu signal handlers for MMU / self modifying code handling */
-#if !defined(CONFIG_SOFTMMU)
-
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
- {
- stack_t stk;
- signal_stack = memalign(16, SIGNAL_STACK_SIZE);
- stk.ss_sp = signal_stack;
- stk.ss_size = SIGNAL_STACK_SIZE;
- stk.ss_flags = 0;
-
- if (sigaltstack(&stk, NULL) < 0) {
- fprintf(logfile, "sigaltstack returned error %d\n", errno);
- exit(1);
- }
- }
-#endif
- {
- struct sigaction act;
-
- sigfillset(&act.sa_mask);
- act.sa_flags = SA_SIGINFO;
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
- act.sa_flags |= SA_ONSTACK;
-#endif
- act.sa_sigaction = host_segv_handler;
- sigaction(SIGSEGV, &act, NULL);
- sigaction(SIGBUS, &act, NULL);
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
- sigaction(SIGFPE, &act, NULL);
-#endif
- }
-#endif
-
-#ifndef _WIN32
- {
- struct sigaction act;
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &act, NULL);
- }
-#endif
- init_timers();
-
qemu_set_fd_handler(xenstore_fd(), xenstore_process_event, NULL, NULL);
machine->init(ram_size, vga_ram_size, boot_device,
kernel_filename, kernel_cmdline, initrd_filename,
timeoffset);
+ /* init USB devices */
+ if (usb_enabled) {
+ for(i = 0; i < usb_devices_index; i++) {
+ if (usb_device_add(usb_devices[i]) < 0) {
+ fprintf(stderr, "Warning: could not add USB device %s\n",
+ usb_devices[i]);
+ }
+ }
+ }
+
if (vnc_display == -1) {
gui_timer = qemu_new_timer(rt_clock, gui_update, NULL);
qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock));
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include "audio/audio.h"
#include "xenctrl.h"
#include "xs.h"
#endif
#ifdef _WIN32
+#include <windows.h>
+#define fsync _commit
#define lseek _lseeki64
#define ENOTSUP 4096
-/* XXX: find 64 bit version */
-#define ftruncate chsize
+extern int qemu_ftruncate64(int, int64_t);
+#define ftruncate qemu_ftruncate64
+
static inline char *realpath(const char *path, char *resolved_path)
{
_fullpath(resolved_path, path, _MAX_PATH);
return resolved_path;
}
+
+#define PRId64 "I64d"
+#define PRIx64 "I64x"
+#define PRIu64 "I64u"
+#define PRIo64 "I64o"
#endif
#ifdef QEMU_TOOL
#else
+#include "audio/audio.h"
#include "cpu.h"
#include "gdbstub.h"
extern int smp_cpus;
/* XXX: make it dynamic */
-#if defined (TARGET_PPC)
+#if defined (TARGET_PPC) || defined (TARGET_SPARC64)
#define BIOS_SIZE ((512 + 32) * 1024)
#elif defined(TARGET_MIPS)
#define BIOS_SIZE (128 * 1024)
int qemu_add_polling_cb(PollingFunc *func, void *opaque);
void qemu_del_polling_cb(PollingFunc *func, void *opaque);
+#ifdef _WIN32
+/* Wait objects handling */
+typedef void WaitObjectFunc(void *opaque);
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+#endif
+
/* character device */
#define CHR_EVENT_BREAK 0 /* serial break char */
extern int64_t ticks_per_sec;
extern int pit_min_timer_count;
+int64_t cpu_get_ticks(void);
void cpu_enable_ticks(void);
void cpu_disable_ticks(void);
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
int bdrv_commit(BlockDriverState *bs);
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
+/* Ensure contents are flushed to disk. */
+void bdrv_flush(BlockDriverState *bs);
#define BDRV_TYPE_HD 0
#define BDRV_TYPE_CDROM 1
#define PCI_ROM_SLOT 6
#define PCI_NUM_REGIONS 7
+
+#define PCI_DEVICES_MAX 64
+
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
struct PCIDevice {
/* PCI config space */
uint8_t config[256];
/* do not access the following fields */
PCIConfigReadFunc *config_read;
PCIConfigWriteFunc *config_write;
+ /* ??? This is a PC-specific hack, and should be removed. */
int irq_index;
};
void generic_pci_save(QEMUFile* f, void *opaque);
int generic_pci_load(QEMUFile* f, void *opaque, int version_id);
-extern struct PIIX3State *piix3_state;
+typedef void (*pci_set_irq_fn)(PCIDevice *pci_dev, void *pic,
+ int irq_num, int level);
+PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min);
+
+void pci_nic_init(PCIBus *bus, NICInfo *nd);
+void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
+uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
+int pci_bus_num(PCIBus *s);
+void pci_for_each_device(void (*fn)(PCIDevice *d));
-PCIBus *i440fx_init(void);
-void piix3_init(PCIBus *bus);
-void pci_bios_init(void);
void pci_info(void);
-/* temporary: will be moved in platform specific file */
-void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque);
+/* prep_pci.c */
PCIBus *pci_prep_init(void);
-PCIBus *pci_grackle_init(uint32_t base);
-PCIBus *pci_pmac_init(void);
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base);
-void pci_nic_init(PCIBus *bus, NICInfo *nd);
+/* grackle_pci.c */
+PCIBus *pci_grackle_init(uint32_t base, void *pic);
+
+/* unin_pci.c */
+PCIBus *pci_pmac_init(void *pic);
+
+/* apb_pci.c */
+PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
+ void *pic);
+
+PCIBus *pci_vpb_init(void *pic);
+
+/* piix_pci.c */
+PCIBus *i440fx_init(void);
+int piix3_init(PCIBus *bus);
+void pci_bios_init(void);
/* openpic.c */
typedef struct openpic_t openpic_t;
/* vga.c */
-#define VGA_RAM_SIZE (4096 * 1024)
+#define VGA_RAM_SIZE (8192 * 1024)
struct DisplayState {
uint8_t *data;
int linesize;
int depth;
+ int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */
int width;
int height;
void *opaque;
BlockDriverState *hd0, BlockDriverState *hd1);
void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
int secondary_ide_enabled);
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table);
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn);
int pmac_ide_init (BlockDriverState **hd_table,
SetIRQFunc *set_irq, void *irq_opaque, int irq);
+/* cdrom.c */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
+
/* es1370.c */
int es1370_init (PCIBus *bus, AudioState *s);
void pci_rtl8139_init(PCIBus *bus, NICInfo *nd);
+/* pcnet.c */
+
+void pci_pcnet_init(PCIBus *bus, NICInfo *nd);
+
/* pckbd.c */
void kbd_init(void);
void pcspk_init(PITState *);
int pcspk_audio_init(AudioState *);
+/* acpi.c */
+extern int acpi_enabled;
+void piix4_pm_init(PCIBus *bus, int devfn);
+void acpi_bios_init(void);
+
/* pc.c */
extern QEMUMachine pc_machine;
extern QEMUMachine isapc_machine;
+extern int fd_bootchk;
void ioport_set_a20(int enable);
int ioport_get_a20(void);
/* usb ports of the VM */
-#define MAX_VM_USB_PORTS 8
+void qemu_register_usb_port(USBPort *port, void *opaque, int index,
+ usb_attachfn attach);
-extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
-extern USBDevice *vm_usb_hub;
+#define VM_USB_HUB_SIZE 8
void do_usb_add(const char *devname);
void do_usb_del(const char *devname);
void usb_info(void);
+/* scsi-disk.c */
+typedef struct SCSIDevice SCSIDevice;
+typedef void (*scsi_completionfn)(void *, uint32_t, int);
+
+SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
+ scsi_completionfn completion,
+ void *opaque);
+void scsi_disk_destroy(SCSIDevice *s);
+
+int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun);
+int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len);
+int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len);
+
+/* lsi53c895a.c */
+void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
+void *lsi_scsi_init(PCIBus *bus, int devfn);
+
/* integratorcp.c */
extern QEMUMachine integratorcp926_machine;
extern QEMUMachine integratorcp1026_machine;
/* tc58128.c */
int tc58128_init(struct SH7750State *s, char *zone1, char *zone2);
+/* NOR flash devices */
+typedef struct pflash_t pflash_t;
+
+pflash_t *pflash_register (target_ulong base, ram_addr_t off,
+ BlockDriverState *bs,
+ target_ulong sector_len, int nb_blocs, int width,
+ uint16_t id0, uint16_t id1,
+ uint16_t id2, uint16_t id3);
+
#endif /* defined(QEMU_TOOL) */
/* monitor.c */
typedef int VncReadEvent(VncState *vs, char *data, size_t len);
+typedef void VncWritePixels(VncState *vs, void *data, int size);
+
+typedef void VncSendHextileTile(VncState *vs,
+ int x, int y, int w, int h,
+ uint32_t *last_bg,
+ uint32_t *last_fg,
+ int *has_bg, int *has_fg);
+
+#if 0
+#define VNC_MAX_WIDTH 2048
+#define VNC_MAX_HEIGHT 2048
+#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
+#endif
+
struct VncState
{
QEMUTimer *timer;
int has_update; /* there's outstanding updates in the
* visible area */
char *old_data;
- int depth;
+ int depth; /* internal VNC frame buffer byte per pixel */
int has_resize;
int has_hextile;
Buffer output;
Buffer input;
kbd_layout_t *kbd_layout;
- int ctl_keys; /* Ctrl+Alt starts calibration */
+ /* current output mode information */
+ VncWritePixels *write_pixels;
+ VncSendHextileTile *send_hextile_tile;
+ int pix_bpp, pix_big_endian;
+ int red_shift, red_max, red_shift1;
+ int green_shift, green_max, green_shift1;
+ int blue_shift, blue_max, blue_shift1;
VncReadEvent *read_handler;
size_t read_handler_expect;
int visible_h;
int slow_client;
+
+ int ctl_keys; /* Ctrl+Alt starts calibration */
};
#define DIRTY_PIXEL_BITS 64
static void vnc_client_read(void *opaque);
static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h);
+#if 0
+static inline void vnc_set_bit(uint32_t *d, int k)
+{
+ d[k >> 5] |= 1 << (k & 0x1f);
+}
+
+static inline void vnc_clear_bit(uint32_t *d, int k)
+{
+ d[k >> 5] &= ~(1 << (k & 0x1f));
+}
+
+static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
+{
+ int j;
+
+ j = 0;
+ while (n >= 32) {
+ d[j++] = -1;
+ n -= 32;
+ }
+ if (n > 0)
+ d[j++] = (1 << n) - 1;
+ while (j < nb_words)
+ d[j++] = 0;
+}
+
+static inline int vnc_get_bit(const uint32_t *d, int k)
+{
+ return (d[k >> 5] >> (k & 0x1f)) & 1;
+}
+
+static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
+ int nb_words)
+{
+ int i;
+ for(i = 0; i < nb_words; i++) {
+ if ((d1[i] & d2[i]) != 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
static void set_bits_in_row(VncState *vs, uint64_t *row,
int x, int y, int w, int h)
{
framebuffer_set_updated(vs, 0, 0, ds->width, ds->height);
}
+/* fastest code */
+static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
+{
+ vnc_write(vs, pixels, size);
+}
+
+/* slowest but generic code. */
+static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
+{
+ unsigned int r, g, b;
+
+ r = (v >> vs->red_shift1) & vs->red_max;
+ g = (v >> vs->green_shift1) & vs->green_max;
+ b = (v >> vs->blue_shift1) & vs->blue_max;
+ v = (r << vs->red_shift) |
+ (g << vs->green_shift) |
+ (b << vs->blue_shift);
+ switch(vs->pix_bpp) {
+ case 1:
+ buf[0] = v;
+ break;
+ case 2:
+ if (vs->pix_big_endian) {
+ buf[0] = v >> 8;
+ buf[1] = v;
+ } else {
+ buf[1] = v >> 8;
+ buf[0] = v;
+ }
+ break;
+ default:
+ case 4:
+ if (vs->pix_big_endian) {
+ buf[0] = v >> 24;
+ buf[1] = v >> 16;
+ buf[2] = v >> 8;
+ buf[3] = v;
+ } else {
+ buf[3] = v >> 24;
+ buf[2] = v >> 16;
+ buf[1] = v >> 8;
+ buf[0] = v;
+ }
+ break;
+ }
+}
+
+static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
+{
+ uint32_t *pixels = pixels1;
+ uint8_t buf[4];
+ int n, i;
+
+ n = size >> 2;
+ for(i = 0; i < n; i++) {
+ vnc_convert_pixel(vs, buf, pixels[i]);
+ vnc_write(vs, buf, vs->pix_bpp);
+ }
+}
+
static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
{
int i;
row = vs->ds->data + y * vs->ds->linesize + x * vs->depth;
for (i = 0; i < h; i++) {
- vnc_write(vs, row, w * vs->depth);
+ vs->write_pixels(vs, row, w * vs->depth);
row += vs->ds->linesize;
}
}
#include "vnchextile.h"
#undef BPP
+#define GENERIC
+#define BPP 32
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
{
int i, j;
int has_fg, has_bg;
uint32_t last_fg32, last_bg32;
- uint16_t last_fg16, last_bg16;
- uint8_t last_fg8, last_bg8;
vnc_framebuffer_update(vs, x, y, w, h, 5);
has_fg = has_bg = 0;
for (j = y; j < (y + h); j += 16) {
for (i = x; i < (x + w); i += 16) {
- switch (vs->depth) {
- case 1:
- send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
- &last_bg8, &last_fg8, &has_bg, &has_fg);
- break;
- case 2:
- send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
- &last_bg16, &last_fg16, &has_bg, &has_fg);
- break;
- case 4:
- send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
- &last_bg32, &last_fg32, &has_bg, &has_fg);
- break;
- default:
- break;
- }
+ vs->send_hextile_tile(vs, i, j,
+ MIN(16, x + w - i), MIN(16, y + h - j),
+ &last_bg32, &last_fg32, &has_bg, &has_fg);
}
}
}
static void vnc_client_write(void *opaque)
{
- ssize_t ret;
+ long ret;
VncState *vs = opaque;
ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
static void vnc_client_read(void *opaque)
{
VncState *vs = opaque;
- ssize_t ret;
+ long ret;
buffer_reserve(&vs->input, 4096);
}
}
+static int compute_nbits(unsigned int val)
+{
+ int n;
+ n = 0;
+ while (val != 0) {
+ n++;
+ val >>= 1;
+ }
+ return n;
+}
+
static void set_pixel_format(VncState *vs,
int bits_per_pixel, int depth,
int big_endian_flag, int true_color_flag,
int red_max, int green_max, int blue_max,
int red_shift, int green_shift, int blue_shift)
{
- switch (bits_per_pixel) {
- case 32:
- case 24:
- vs->depth = 4;
- break;
- case 16:
- vs->depth = 2;
- break;
- case 8:
- vs->depth = 1;
- break;
- default:
+ int host_big_endian_flag;
+
+#ifdef WORDS_BIGENDIAN
+ host_big_endian_flag = 1;
+#else
+ host_big_endian_flag = 0;
+#endif
+ if (!true_color_flag) {
+ fail:
vnc_client_error(vs);
- break;
+ return;
+ }
+ if (bits_per_pixel == 32 &&
+ host_big_endian_flag == big_endian_flag &&
+ red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
+ red_shift == 16 && green_shift == 8 && blue_shift == 0) {
+ vs->depth = 4;
+ vs->write_pixels = vnc_write_pixels_copy;
+ vs->send_hextile_tile = send_hextile_tile_32;
+ } else
+ if (bits_per_pixel == 16 &&
+ host_big_endian_flag == big_endian_flag &&
+ red_max == 31 && green_max == 63 && blue_max == 31 &&
+ red_shift == 11 && green_shift == 5 && blue_shift == 0) {
+ vs->depth = 2;
+ vs->write_pixels = vnc_write_pixels_copy;
+ vs->send_hextile_tile = send_hextile_tile_16;
+ } else
+ if (bits_per_pixel == 8 &&
+ red_max == 7 && green_max == 7 && blue_max == 3 &&
+ red_shift == 5 && green_shift == 2 && blue_shift == 0) {
+ vs->depth = 1;
+ vs->write_pixels = vnc_write_pixels_copy;
+ vs->send_hextile_tile = send_hextile_tile_8;
+ } else
+ {
+ /* generic and slower case */
+ if (bits_per_pixel != 8 &&
+ bits_per_pixel != 16 &&
+ bits_per_pixel != 32)
+ goto fail;
+ vs->depth = 4;
+ vs->red_shift = red_shift;
+ vs->red_max = red_max;
+ vs->red_shift1 = 24 - compute_nbits(red_max);
+ vs->green_shift = green_shift;
+ vs->green_max = green_max;
+ vs->green_shift1 = 16 - compute_nbits(green_max);
+ vs->blue_shift = blue_shift;
+ vs->blue_max = blue_max;
+ vs->blue_shift1 = 8 - compute_nbits(blue_max);
+ vs->pix_bpp = bits_per_pixel / 8;
+ vs->pix_big_endian = big_endian_flag;
+ vs->write_pixels = vnc_write_pixels_generic;
+ vs->send_hextile_tile = send_hextile_tile_generic;
}
-
- if (!true_color_flag)
- vnc_client_error(vs);
vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height);
vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
vnc_write_u8(vs, vs->depth * 8); /* depth */
+#ifdef WORDS_BIGENDIAN
+ vnc_write_u8(vs, 1); /* big-endian-flag */
+#else
vnc_write_u8(vs, 0); /* big-endian-flag */
+#endif
vnc_write_u8(vs, 1); /* true-color-flag */
if (vs->depth == 4) {
vnc_write_u16(vs, 0xFF); /* red-max */
vnc_write_u8(vs, 16); /* red-shift */
vnc_write_u8(vs, 8); /* green-shift */
vnc_write_u8(vs, 0); /* blue-shift */
+ vs->send_hextile_tile = send_hextile_tile_32;
} else if (vs->depth == 2) {
vnc_write_u16(vs, 31); /* red-max */
vnc_write_u16(vs, 63); /* green-max */
vnc_write_u8(vs, 11); /* red-shift */
vnc_write_u8(vs, 5); /* green-shift */
vnc_write_u8(vs, 0); /* blue-shift */
+ vs->send_hextile_tile = send_hextile_tile_16;
} else if (vs->depth == 1) {
- vnc_write_u16(vs, 3); /* red-max */
+ /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */
+ vnc_write_u16(vs, 7); /* red-max */
vnc_write_u16(vs, 7); /* green-max */
vnc_write_u16(vs, 3); /* blue-max */
vnc_write_u8(vs, 5); /* red-shift */
vnc_write_u8(vs, 2); /* green-shift */
vnc_write_u8(vs, 0); /* blue-shift */
+ vs->send_hextile_tile = send_hextile_tile_8;
}
+ vs->write_pixels = vnc_write_pixels_copy;
vnc_write(vs, pad, 3); /* padding */
#define CONCAT_I(a, b) a ## b
#define CONCAT(a, b) CONCAT_I(a, b)
#define pixel_t CONCAT(uint, CONCAT(BPP, _t))
-
-static void CONCAT(send_hextile_tile_, BPP)(VncState *vs,
- int x, int y, int w, int h,
- pixel_t *last_bg, pixel_t *last_fg,
- int *has_bg, int *has_fg)
+#ifdef GENERIC
+#define NAME generic
+#else
+#define NAME BPP
+#endif
+
+static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
+ int x, int y, int w, int h,
+ uint32_t *last_bg32,
+ uint32_t *last_fg32,
+ int *has_bg, int *has_fg)
{
char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth);
pixel_t *irow = (pixel_t *)row;
int j, i;
+ pixel_t *last_bg = (pixel_t *)last_bg32;
+ pixel_t *last_fg = (pixel_t *)last_fg32;
pixel_t bg = 0;
pixel_t fg = 0;
int n_colors = 0;
has_color = 1;
} else if (irow[i] != color) {
has_color = 0;
-
+#ifdef GENERIC
+ vnc_convert_pixel(vs, data + n_data, color);
+ n_data += vs->pix_bpp;
+#else
memcpy(data + n_data, &color, sizeof(color));
- hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1);
- n_data += 2 + sizeof(pixel_t);
+ n_data += sizeof(pixel_t);
+#endif
+ hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+ n_data += 2;
n_subtiles++;
min_x = -1;
}
}
if (has_color) {
- memcpy(data + n_data, &color, sizeof(color));
- hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1);
- n_data += 2 + sizeof(pixel_t);
+#ifdef GENERIC
+ vnc_convert_pixel(vs, data + n_data, color);
+ n_data += vs->pix_bpp;
+#else
+ memcpy(data + n_data, &color, sizeof(color));
+ n_data += sizeof(pixel_t);
+#endif
+ hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
+ n_data += 2;
n_subtiles++;
}
irow += vs->ds->linesize / sizeof(pixel_t);
vnc_write_u8(vs, flags);
if (n_colors < 4) {
if (flags & 0x02)
- vnc_write(vs, last_bg, sizeof(pixel_t));
+ vs->write_pixels(vs, last_bg, sizeof(pixel_t));
if (flags & 0x04)
- vnc_write(vs, last_fg, sizeof(pixel_t));
+ vs->write_pixels(vs, last_fg, sizeof(pixel_t));
if (n_subtiles) {
vnc_write_u8(vs, n_subtiles);
vnc_write(vs, data, n_data);
}
} else {
for (j = 0; j < h; j++) {
- vnc_write(vs, row, w * vs->depth);
+ vs->write_pixels(vs, row, w * vs->depth);
row += vs->ds->linesize;
}
}
}
+#undef NAME
#undef pixel_t
#undef CONCAT_I
#undef CONCAT